MyBatis 越过Mapper动态代理–从会话到执行器的逻辑初次梳理
JDBC 执行过程
获取连接–》预编译SQL–》设置参数–》执行SQL
三种操作数据库的statement
-
简单执行器 Statement
-
预处理执行器 Prepared Statement 防注入
-
存储过程执行器 Callable Statement
MyBatis 执行体系 (主流程)
一、 sqlSession 对应的功能有提交会话和关闭会话。因为不能保证线程安全,所以不能跨线程调用。
只提供会话,不执行操作,具体操作交给执行器Executor
二、Executor 基本功能 改、查 、维护缓存 辅助功能 提交、关闭执行器 刷新批处理
三、Statement Handler 是对jdbc 参数设置、结果处理的具体处理
注意:一个sqlsession会话 对应一个executor,一个executor对应多个StatementHandler
三种执行器
默认使用的执行器为SimpleExcutor
BaseExcutor、CachingExecutor、SimpleExcutor、ReuseExecutor、BatchExecutor
其中CachingExecutor(二级缓存执行器) 是通过装饰器模式添加,对应的功能包括缓存处理、事务处理、
重用处理以及批处理,这些共性是在同一个会话中多个SQL执行才具有的
SimpleExcutor:每次处理都会创建一个新的预处理器(PrepareStatement)
ReuseExecutor: 相同的SQL只进行一次预处理
BatchExecutor:批处理提交修改必须执行flushStatements才能生效
三种(SimpleExcutor、ReuseExecutor、BatchExecutor)执行器的区别与互通点
一、都是继承了BaseExecutor抽象类,目的是为了实现MyBatis的一级缓存的实现
二、都对应三种Statement(Statement、PrepareStatement、CallableStatement)
也就是对应的对应数据库的三次不同的交互模式(
1、Statement:每次发送一条静态SQL
2、PrepareStatement:发送一次SQL多次参数,因为具有预编译的方式
3、CallableStatement:发送一次 传输多条SQL和多个参数,之针对修改有效)
三、SimpleExcutor 执行静态SQL、批处理、设置加载的行数范围BoundRow
四、针对与JDBC的Statement对于相同的sqlsession会话,三种执行器调用不同的
的方法,最后编译相同的SQL都会在使用相同的Statement
BatchExcutor 批处理提交对应的session
JDBC 的Statement 在 sqlsession、MapperStatement、执行的SQL是连续的就会使用相同的Statement
基础执行器与一级缓存
一级缓存在BaseExcutor中执行
1、命中场景–默认打开
运行时参数相关
1、SQL和参数相同 命中一级缓存
2、相同的StatementID(全定限名点方法)-----》对应的相同的Mapper接口定义的方法名不同
3、sqlSession 必须相同
4、RowBounds 相同 (返回值行数范围)
操作与配置相关
1、未手动清空
2、未调用 flushCache=true 的查询
3、未执行Update
4、缓存作用域不是STATEMNET-->嵌套查询 对应改的属性localcachescope
2、会话缓存清空位置
手动flushCache清空、配置flushCache=true、执行Update操作、
全局配置localcachescope属性STATEMENT
针对修改update操作时,会将当前会话的所有的缓存都清空! 因为会话的生命周期是短暂的,所 以没必要针对于修改的部分进行清空,直接全部清空当前会话的缓存也就是一级缓存。
class BaseExcutor implements Executor {
protected PerpetualCache localCache;
//.....
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource())
.activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();
return doUpdate(ms, parameter);
}
//.....
@Override
public void clearLocalCache() {
if (!closed) {
localCache.clear();//执行缓存清除操作
localOutputParameterCache.clear();
}
}
}
//缓存类
public class PerpetualCache implements Cache {
private Map<Object, Object> cache = new HashMap<>();
@Override
public void clear() {
cache.clear();
}
}
最后结合执行器的缓存总体流程
如有错误地方,欢迎大家指正