Mybatis源码浅析、定制原理及方法

mybatis为javaer们提供了强大的数据库访问支持,但对于绝大多数场景来说,使用上仍然不够简单,比如:还是需要编写包含sql语句的xml或注解。本文对mybatis的原理进行了简单的介绍,并介绍了我们部门自己基于mybatis源代码修改并开发的mybatis扩展框架appassist-dao.

1.Mybatis基础

1.两种Mybatis使用方式

  1. spring集成方式
  2. 直接调用初始化方式
    • 下图时两种初始化方式之间的关系
      这里写图片描述
      图1

2.Mybatis-spring的初始化流程

  • mybatis-spring是对mybatis的封装,因此实际上mybatis-spring的初始化流程包含了标准的mybais初始化流程。下图展示了mybatis-spring初始化的大体流程,其中红框部分会进行mapper xml的扫描,也就是右侧的流程部分。
    这里写图片描述

    图2

  • mybatis-spring除了可以使用SqlSessionFacotryBean来初始化各个mapper,还可以用MapperScanConfigurer来扫描指定包路径下的Mapper接口,自动向spring框架中注入对应的Mapper实现:
    这里写图片描述

    图3

4. Mybatis两种使用模式—— 传统模式SqlSession和MapperProxy:

图4,图5来源:https://github.com/nero520/mybatis

传统模式,使用SqlSession进行访问:
这里写图片描述

图4

MapperProxy模式:
这里写图片描述
图5

3. MapperProxy做了些什么?

MapperProxy实际上是一个JDK代理:InvocationHandler。被代理的,则是与xxxMapper.xml中namespace对应的接口。
这里写图片描述

图6

4.Mybatis定制——实现基础Dao类:BaseDao,并为继承BaseDao类的Mapper接口自动注入mybatis sql xml。

1)需要定制的功能:

比如,目前在我们部门内测时候用的dao框架 appassist-dao,它定义了一个基础接口,凡是集成自该接口的Dao对象,都会根据它的类型参数”T extends BaseQuery”去生成对应的sql语句。

public interface BaseDao<T extends BaseQuery, KEY extends Serializable> {
    int insert(T instance);
    int insertAll(Collection<T> instances);
    int insertAllBatch(Collection<T> instances);
    int deleteByKeys(KEY... keys);
    int deleteByCondition(T condition);
    List<T> selectListByCondition(T condition);
    T selectOneByKey(KEY key);
    T selectOneByCondition(T condition, boolean strictlyCheck) throws SelectOneException;
    int selectCount(T condition);
    List<T> selectListByKeys(KEY... keys);
    int updateByKey(T instance);
    int updateByCondition(@Param("update") T update, @Param("condition") T condition);
}

举个例子:
我们定义一个Dao,并定义对应的Domain对象(即PO对象)。

public interface UserDao extends BaseDao<User, Long> {
}
@Table("sys_user")
public class User extends BaseQuery {
    @Column(primaryKey = true)
    private Long id;

    @Column
    private String name;

    @Column("age")
    private Integer age;

    @Column("health_condition")
    private String healthCondition;
}

appassist-dao可以使得数据库访问变得更简单,就如上述两个类:User和UserDao。只要将UserDao扫描并实例化注入到spring中,就能够像如下使用:

@Resource
private UserDao userDao;
@Override
public void testUserDao() {
    User user1 = new User();
    user1.setName("haha");
    User user2 = new User();
    user2.setName("hehe");

    // 将name为"haha"和"hehe"的两个User插入sys_user表中。
    int insertCount = userDao.insertAll(Arrays.asList(user1, user2)); 
}

2)定制功能的实现

前面有讲到,spring中,Mybatis的初始化入口为:SqlSessionFactoryBean。为了在mybatis初始化的时候能够扫描UserDao和User类,并根据User类中的注解自动生成sql注册到Mybatis中。我们需要对它进行改写。
一共有两个hack点:
1. 图2中的绿色部分
这里写图片描述
对应mybatis源码:

MybatisXMLMapperBuilder.parse();

这里写图片描述

  1. MapperScannerConfigurer将对象自动扫描注入后,对Dao接口方法进行注解扫描
    对应mybatis源码:
MybatisMapperAnnotationBuilder.parse();

这里写图片描述

其中红框部分即为我们自己添加的Sql自动生成并注册mybatis的代码。
AutoSqlInjector中,根据Domain对象中Table、Column注解等信息,生成对应的BaseDao中方法所对应的mybatis sql片段。再通过调用

builderAssistant.addMappedStatement

方法,来将生成好sql片段注册到mybatis中。

3)这样定制带来的几大好处

  1. mybatis orm化,对于大多数应用场景无需mapper xml文件,即可使用。
  2. 采用了比较好的Mybatis实践来实现方法,由sql技术大牛统一编写mybatis sql,避免大多数情况下自己编写sql导致的问题。
  3. 能够植入一些mybatis不具备的特别的功能,比如dao方法监控自动接入、分库分表、过滤空条件update和delete。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章