MyBatis共有两级缓存
-
一级缓存:在Base Executor实现
-
二级缓存:在Caching Executor实现
一级缓存命中条件
一级缓存不能打开,存储结构为Key-Value形式,底层为一个HashMap,当一级缓存命中时,Sql只会被编译处理一次
作用:当执行完一句查SQL的时候,再调用时,产生的两个对象是一致的,而且SQL只被编译和使用一次,因为第二次调用的时候,取得对象是从一级缓存中取得
命中相关条件
-
运行时参数相关
-
操作与配置相关
命中条件
-
Sql和参数相同
-
statementID要一样
-
方法名不一样,接口名不一样,也就是方法的全限定名称不一样都会导致StatementID不一样
-
不同的会话,执行相同的Sql的StateMentID会不一样(一级缓存被称为Session缓存)
-
使用不同的RowBounds进行分页,也会导致StatementID不一样
-
查询后清空缓存也不会命中缓存
-
方法加上注解flushCache=true
-
调用session的clearCache方法
-
当主动去调用mapper进行增删改操作的时候(这个增删改的判定是根据注解和配置形式来决定的,而不是sql决定,比如@Delete(select * …)也会被视作删除操作从而清空缓存),也会自动清空一次缓存(否则会产生数据一致性问题)
-
关闭一级缓存,修改localCacheScope改成STATEMENT(但此时不是真正关闭,嵌套查询依然会走缓存)
-
子查询不会清空缓存,因为子查询是要依赖一级缓存的
所以总的来说
运行时参数
-
sql和参数相同
-
相同的statementID,即方法的全限定名称一样
-
sqlSession一样(会话级缓存)
-
RowBounds分页也一样
操作与配置
-
不清空缓存(提交、回滚操作都会清空缓存,还有手动清空)
-
不配置flushCache=true
-
不执行update语句,即不执行增删改语句
-
启用一级缓存,也就是缓存的作用域不改为STATEMENT
一级缓存源码解析
首先认识MyBatis执行SQl的一套流程
-
动态代理Mapper
-
创建SqlSession
-
SqlSession中调用Executor
-
Executor调用StatementHandler去处理SQL
-
在数据库执行SQL
而一级缓存(LocalCache)的调用,就在Executor中,具体来说是在BaseExecutor中,(BaseExecutor执行query方法时,会先查看是否存在一级缓存,不存在会执行doQuery方法(这个方法的具体实现是在调用的BaseExecutor实例中,将SQL放入数据库里面执行后,然后填充缓存),存在则使用PerpeturalCache,一级缓存的实现是在PerpetualCache中的,不需要继续走数据库执行SQL
一级缓存结构
一级缓存具体的结构其实是一个HashMap
-
Key:由SQL、Ses