MyBatis代理模式开发

前面已经使用MyBatis完成了对Emp表的CRUD操作,都是由SqlSession调用自身方法发送SQL命令并得到结果的,实现了MyBatis的入门。但是却存在如下缺点:

  • 不管是selectList()、selectOne()、selectMap(),都是通过SQLSession对象的API完成增删改查,都只能提供一个查询参数。如果要多个参数,需要封装到JavaBean或者Map中,比较麻烦。
  • 返回值类型较固定。
  • 只提供了映射文件,没有提供数据库操作的接口,不利于后期的维护扩展。

MyBatis中提供了另外一种成为Mapper代理(或称为接口绑定)的操作方式。在实际开发中也使用该方式。下面我们就是要Mapper代理的方式来实现对Emp表的CRUD操作吧,还有完成多个参数传递、模糊查询、自增主键回填等更多的技能实现。 优点如下:

  • 接口 模块之间有规范了
  • 参数的处理多样了,接口中的方法参数列表由我们自己决定
  • 通过代理模式由mybatis提供接口的实现类对象 我们不用写实现类了

一、使用Mapper代理方式实现查询

1.1.准备接口文件

在mapper包下创建接口 EmpMapper,代码如下:

public interface EmpMapper {
    /*查询所有员工接口
     * 返回所有员工封装在一起的Emp List集合*/
    List<Emp> findAllEmp();
}

1.2.准备映射文件

这里的映射文件必须和EmpMapper在同一个目录中,否则会出错误内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--
namespace需要指定接口文件的路径
-->
<mapper namespace="com.augus.mapper.EmpMapper">
    <!--
    1 接口的名字和Mapper映射为文件名字必须保持一致(不包含拓展名)
    2 Mapper映射文件的namespace必须是接口的全路径名
    3 sql语句的id必须是对应方法的名
    4 EmpMapper映射文件应该和接口编译之后放在同一个目录下
    List<Emp> findAllEmp();
    -->

    <select id="findAllEmp" resultType="com.augus.pojo.Emp">
        select * from emp
    </select>
</mapper>

1.3.sqlMapConfig.xml核心配置文件中添加映射文件

注意这里配置的时候要使用之前讲过的方式一:通过mapper映射文件的文件路径导入 使用的mapper标签的resource属性

<mappers>
        <!--mapper映射文件的文件路径导入-->
        <mapper resource="com\augus\mapper\EmpMapper.xml"/>
        <mapper resource="com\augus\mapper\DeptMapper.xml"/>
    </mappers>

截图如下:

1.4.创建测试代码

创建测试代码,测试结果如下:

public class Test02 {
    private SqlSession sqlSession;
    @BeforeEach
    public void setUp(){
        SqlSessionFactoryBuilder ssfb =new SqlSessionFactoryBuilder();
        InputStream resourceAsStream = null;
        try {
            resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactory factory=ssfb.build(resourceAsStream) ;
        sqlSession=factory.openSession();
    }

    //查询所有员工
    @Test
    public void testFindAllDept(){
        /*获取字节码文件*/
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);

        //执行SQL
        List<Emp> allEmp = mapper.findAllEmp();

        for (Emp emp : allEmp) {
            System.out.println(emp);
        }
    }

    @AfterEach
    public void tearDown(){
        //关闭
        sqlSession.close();
    }

}

二、Mapper代理模式浅析

回顾上面测试代码写法:

public static void main(String[] args) {
    //前三步都相同
    InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = factory.openSession();
    //这里不再调用SqlSession的api,而是获得了接口对象,调用接口中的方法。
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> list = mapper.getUserByName("tom");
}

通常的EmpMapper接口都没有实现的方法却可以使用,是为什么呢?

原因是使用了—动态代理,MyBatis初始化时对接口的处理:MapperRegistry是Configuration中的一个属性, 它内部维护一个HashMap用于存放mapper接口的工厂类,每个接口对应一个工厂类。mappers中可以 配置接口的包路径,或者某个具体的接口类。

<mappers>
        <!--mapper映射文件的文件路径导入-->
        <mapper resource="com\augus\mapper\EmpMapper.xml"/>
        <mapper resource="com\augus\mapper\DeptMapper.xml"/>
</mappers>

当解析mappers标签时,会判断解析到的是mapper配置文件时,会再将对应配置文件中的增删改查 标签 封装成MappedStatement对象,存入mappedStatements中。当判断解析到接口时,会 建此接口对应的MapperProxyFactory对象,存入HashMap中,key=接口的字节码对象,value =此接口对应的MapperProxyFactory对象。

posted @ 2022-08-03 10:26  酒剑仙*  阅读(101)  评论(0)    收藏  举报