一、关键类
Configuration
配置类。
MapperProxy
代理mybatis的mapper接口的代理对象。执行invoke。
创建过程:
MapperMethod
mapper代理对象最终执行MapperMethod。
SqlSession
SqlSession 由 SqlSessionFactory创建,并包含了操作数据的所有接口。默认实现是DefaultSqlSession,spring管理的实现SqlSessionTemplate。
SqlSessionFactory接口 主要负责开启session。
SqlSession 包含的方法:
与SqlSessionFactory关系与默认实现类:
Executor
SQL 的执行引擎,负责增删改查的具体操作,每个Sqlsession都会有一个executor对象。相当于jdbc中的statement封装版。
BaseExecutor有三个子类采用适配器模式。BaseExecutor的query 会先查一级缓存,
SimpleExecutor 主要是statement用完就关闭。
ReuseExecutor 对重用statement。
BatchExecutor 批处理sql。
CachingExecutor是Executor的二级缓存。
继承关系:
localCache一级缓存调用过程,通过KEY调用:
缓存
PerpetualCache 存在Executor中,每一个sqlsession的都有一个Executor,随sqlsession会话的生命周期销毁。
一级缓存 默认使用,由KEY级别,Hash存储结果。同一个session可公用缓存。不能多个会话或分布式环境中。
二级缓存 手动开启。 是namespace级别。与应用生命周期相同。
查询数据的顺序:二级缓存 —> 一级缓存 —> 数据库。
其他缓存
BoundSql
保存SQL和参数的对象。
StatementHandler接口
JDBC的statement封装,用于SQL传参。存在Executor中。
四种实现:
Roting** 主要其他三个的创建和调用。
Simple** 简单sql的处理。没有参数。
Prepared** 预处理SQL。有参数,由DefaultParameterHandler.setParameters处理参数。
Call** 存储过程相关。
预处理参数。
ResultSetHandler
结果处理器。BaseStatementHandler 执行器之后获取结果。
调用过程
SqlSessionTemplate代理DefaultSqlSession对象。
SqlSession线程安全问题
总结:直接使用DefaultSqlSession不是线程安全,SqlSessionTemplate,SqlSessionManager安全,但是采用代理方式消耗内存。
DefaultSqlSession不安全的原因
DefaultSqlSession不是线程安全,SqlSession维度的connection。两个线程共用的一个SqlSession,其中一个线程关闭会导致另一个线程不可用。从SqlSession中取得executor。
安全方式使用DefaultSqlSession
由spring管理的SqlSessionTemplate 是线程安全。在获取connection时,使用JDK代理的方式每次都获取sesson。sessionHolder中保持sesson。
最终创建sqlSession的过程,在DefaultSqlSessionFactory中创建的DefaultSqlSession,因此由spring管理的crud调用最终都会到DefaultSqlSession中实现。
SqlSessionManager 线程安全
SqlSessionManager 线程安全,不过采用ThreadLocal方式保持当前sqlsession。也是采用代理方式,每次都获取sqlsession。
代理相关知识
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");//执行新增方法 } }复制代码