一、关键类

Configuration 

配置类。

MapperProxy

代理mybatis的mapper接口的代理对象。执行invoke。

创建过程:

mybatis-源码解读_mybatis

MapperMethod

mapper代理对象最终执行MapperMethod。

mybatis-源码解读_mybatis_02

SqlSession

SqlSession 由 SqlSessionFactory创建,并包含了操作数据的所有接口。默认实现是DefaultSqlSession,spring管理的实现SqlSessionTemplate。

SqlSessionFactory接口 主要负责开启session。

SqlSession 包含的方法:

mybatis-源码解读_mybatis_03

与SqlSessionFactory关系与默认实现类:

mybatis-源码解读_mybatis_04

Executor

SQL 的执行引擎,负责增删改查的具体操作,每个Sqlsession都会有一个executor对象。相当于jdbc中的statement封装版。

BaseExecutor有三个子类采用适配器模式。BaseExecutor的query 会先查一级缓存,

  • SimpleExecutor 主要是statement用完就关闭。

  • ReuseExecutor 对重用statement。

  • BatchExecutor 批处理sql。

CachingExecutor是Executor的二级缓存。

继承关系:

mybatis-源码解读_mybatis_05

localCache一级缓存调用过程,通过KEY调用:mybatis-源码解读_mybatis_06

mybatis-源码解读_mybatis_07

缓存

PerpetualCache 存在Executor中,每一个sqlsession的都有一个Executor,随sqlsession会话的生命周期销毁。

  • 一级缓存 默认使用,由KEY级别,Hash存储结果。同一个session可公用缓存。不能多个会话或分布式环境中。

  • 二级缓存 手动开启。 是namespace级别。与应用生命周期相同。

查询数据的顺序:二级缓存 —> 一级缓存 —> 数据库。

mybatis-源码解读_mybatis_08

mybatis-源码解读_mybatis_09

其他缓存

mybatis-源码解读_mybatis_10

BoundSql

保存SQL和参数的对象。

StatementHandler接口

JDBC的statement封装,用于SQL传参。存在Executor中。

四种实现:

  • Roting** 主要其他三个的创建和调用。

  • Simple** 简单sql的处理。没有参数。

  • Prepared** 预处理SQL。有参数,由DefaultParameterHandler.setParameters处理参数。

  • Call** 存储过程相关。

mybatis-源码解读_mybatis_11

预处理参数。

mybatis-源码解读_mybatis_12

ResultSetHandler

结果处理器。BaseStatementHandler 执行器之后获取结果。

mybatis-源码解读_mybatis_13

调用过程

mybatis-源码解读_mybatis_14

SqlSessionTemplate代理DefaultSqlSession对象。

mybatis-源码解读_mybatis_15

mybatis-源码解读_mybatis_16

SqlSession线程安全问题

总结:直接使用DefaultSqlSession不是线程安全,SqlSessionTemplate,SqlSessionManager安全,但是采用代理方式消耗内存。

DefaultSqlSession不安全的原因

DefaultSqlSession不是线程安全,SqlSession维度的connection。两个线程共用的一个SqlSession,其中一个线程关闭会导致另一个线程不可用。从SqlSession中取得executor。

mybatis-源码解读_mybatis_17

安全方式使用DefaultSqlSession

由spring管理的SqlSessionTemplate 是线程安全。在获取connection时,使用JDK代理的方式每次都获取sesson。sessionHolder中保持sesson。

mybatis-源码解读_mybatis_18

mybatis-源码解读_mybatis_19

mybatis-源码解读_mybatis_20

mybatis-源码解读_mybatis_21

mybatis-源码解读_mybatis_22

最终创建sqlSession的过程,在DefaultSqlSessionFactory中创建的DefaultSqlSession,因此由spring管理的crud调用最终都会到DefaultSqlSession中实现。

mybatis-源码解读_mybatis_23

SqlSessionManager 线程安全

SqlSessionManager 线程安全,不过采用ThreadLocal方式保持当前sqlsession。也是采用代理方式,每次都获取sqlsession。

mybatis-源码解读_mybatis_24

代理相关知识

JDK代理是对接口进行代理,并指定代理类。因此SqlSessionTemplate实例代理的SqlSession接口最终的实现在DefaultSqlSession。

相当于SqlSessionTemplate对DefaultSqlSession代理。DefaultSqlSession是代理对象。

public class JdkProxy implements InvocationHandler {
    private Object target ;//需要代理的目标对象
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("JDK动态代理,监听开始!");
        Object result = method.invoke(target, args);
        System.out.println("JDK动态代理,监听结束!");
        return result;
    }
    //定义获取代理对象方法
    private Object getJDKProxy(Object targetObject){
        //为目标对象target赋值
        this.target = targetObject;
        //JDK动态代理只能针对实现了接口的类进行代理,newProxyInstance 函数所需参数就可看出
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }
    
    public static void main(String[] args) {
        JdkProxy jdkProxy = new JdkProxy();//实例化JDKProxy对象
        UserManager user = (UserManager) jdkProxy.getJDKProxy(new UserManagerImpl());//获取代理对象
        user.addUser("admin", "123123");//执行新增方法
    }
}复制代码