正在阅读:
- 首页 » 开发运维 » 后端 » Mybatis一级缓存和二级缓存的产生和销毁
Mybatis一级缓存和二级缓存的产生和销毁
一、MyBatis一级缓存
1.MyBatis一级缓存默认是开启的
2.流程:
3.MyBatis命中缓存原则
1.StatmentId必须一致,否则无法命中
2.传递给SQL的参数必须一致,比如,传入的map中有两个参数,只要传入的SQL中的id值是一样的,其他参数是什么没影响
3.分页参数必须相同,缓存粒度的是整个分页结果集,而不是结果集中的对象
RowBounds rowBounds1 = new RowBounds(0, 1); List<TempEntity> tempEntity1 = sqlSession.selectList("com.mybatis.TempDao.list", null, rowBounds1); logger.info(tempEntity1); RowBounds rowBounds2 = new RowBounds(0, 2); List<TempEntity> tempEntity2 = sqlSession.selectList("com.mybatis.TempDao.list", null, rowBounds2); logger.info(tempEntity2); logger.info(tempEntity1 == tempEntity2);
分页参数不一致
4.要求传递给JDBC的SQL语句必须是一致的
<select id="getById3" parameterType="java.util.Map" resultType="com.mybatis.TempEntity"> <if test="type==1"> select * from temp where id = #{id} </if> <if test="type==2"> select * from temp where 1=1 and id = #{id} </if> </select>
虽然,id一致,返回结果一致,但是就是多了where 1=1 ,所以无法命中缓存
5.执行环境必须一致
<environment id="dev"> <!--指定事务管理的类型,这里简单使用Java的JDBC的提交和回滚设置--> <transactionManager type="JDBC"></transactionManager> <!--dataSource 指连接源配置,POOLED是JDBC连接对象的数据源连接池的实现--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mytest"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </dataSource> </environment>
二、一级缓存的生命周期,什么时候产生什么时候销毁
1.什么时候产生:SqlSession中的select、selectOne、selectList、selectMap执行时会产生缓存
2.什么时候销毁
1.sqlSession.close();
2.sqlSession.commit();
3.sqlSession.rollback();
4.sqlSession.clearCache();
5.执行insert、update、delete之后会清空一级缓存,而且即使查询的先查询的表和后更新的表不是一个表也会清空缓存,清空所有session1一级缓存
3.MyBatis一级缓存是否会产生脏读?并不会
由于关闭sqlSession、执行commit、rollback都会清空一级缓存,所以实际上MyBatis一级缓存的生命周期是在数据库事务的生命周期之内。所以不会产生脏读。
三、源码
一级缓存存在哪?
BaseExecutor中这段代码list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
可以找出存在PerpetualCache类的 localCache实例对象中
public class PerpetualCache implements Cache { private final String id; private Map<Object, Object> cache = new HashMap(); public void putObject(Object key, Object value) { this.cache.put(key, value); } public Object getObject(Object key) { return this.cache.get(key); } CachingExecutor: CacheKey key = this.createCacheKey(ms, parameterObject, rowBounds, boundSql);//通过sql,参数生成缓存的key,和一级缓存命中原则有关 BaseExecutor: list = resultHandler == null ? (List)this.localCache.getObject(key) : null; if (list != null) { this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);//如果缓存中有就处理结果 } else { list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);//如果缓存没有查数据库 }
MyBatis与Spring集成
未开启事务
每次请求,Spring都会关闭旧的session在创建新的session,所以此时一级缓存无效。
开启事务
在一个事务内,Spring通过ThreadLocal始终使用同一个session,所以此时一级缓存在事务内有效。
四、二级缓存
1. 开启二级缓存:
1.mybatis.xml->configuration标签下->
<settings> <setting name="cacheEnabled" value="true"/> </settings>
2.mapper.xml加上<cache/>标签
3.类需要序列化
2.二级缓存和一级缓存的区别
一级缓存:每个session查询自己的cache,cache没有数据再查数据库
二级缓存
二级缓存:session1和session2共用一个cache,如果公共cache查不到,就去查数据库
3.二级缓存的命中原则
在同一个SqlSessionFactory中命中原则和一级缓存一样
4.二级缓存什么时候产生,什么时候销毁
产生条件:1.满足一级缓存产生条件
2.sqlSession执行了close或commit
一级缓存和二级缓存联合工作的原理
二级缓存的销毁:
一级缓存销毁是销毁同一个sqlSession中的缓存,二级缓存是销毁同一个mapper映射文件的缓存
二级缓存只有执行update操作才会销毁。
如果不想销毁加flushCache标签
<update id="updateById" parameterType="int" flushCache="false">
</update>
5.二级缓存的源码
CachingExecutor中:
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { Cache cache = ms.getCache();//一个个开启了二级缓存的mapper.xml文件所对应的缓存对象 if (cache != null) { this.flushCacheIfRequired(ms);//二级缓存有数据,判断是否开启flushCache if (ms.isUseCache() && resultHandler == null) {//当前Statement是否开启二级缓存 this.ensureNoOutParams(ms, boundSql);//没有输出参数 List<E> list = (List)this.tcm.getObject(cache, key);//查二级缓存 if (list == null) {//如果二级缓存没有,调代理对象跟一级缓存一样 list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); this.tcm.putObject(cache, key, list);//将查询结果放到二级缓存 } return list; } } return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
数据结构:
CachingExecutor:private final TransactionalCacheManager tcm = new TransactionalCacheManager();
TransactionalCacheManager:private final Map<Cache, TransactionalCache> transactionalCaches = new HashMap();
TransactionalCache:private final Map<Object, Object> entriesToAddOnCommit;
entriesToAddOnCommit:当执行commit时,即将要放到二级缓存的对象,当执行rollback时,就会清空即将要放入二级缓存的对象
执行update时,清空二级缓存
public void clear() { this.clearOnCommit = true; this.entriesToAddOnCommit.clear(); } public void commit() { if (this.clearOnCommit) { this.delegate.clear(); } this.flushPendingEntries(); this.reset(); }
转载请注明文本地址:https://www.bemhome.com/post/28.html