为了账号安全,请及时绑定邮箱和手机立即绑定

二级缓存的过程

问下为啥第一次查询后,返回的结果只写入了一级缓存,返回给客户端。二级缓存没写入呢

正在回答

4 回答

  • sqlSession关闭时才创建二级缓存 

  • sqlSession提交时才创建二级缓存


0 回复 有任何疑惑可以回复我~


Mybatis Cache

一级缓存特点

  1. 自动启用

  • 通过在setting中设置localCacheScope= STATEMENT(默认为SESSION)全局禁用一级缓存

  • 在Dao接口方法上添加注解:@Options(flushCache=Options.FlushCachePolicy.True),禁用这个方法的一级缓存

命中原则,同一SqlSession内,以下5个条件组成key,放入缓存中:

  • 条件一:statementId相同

  • 条件二:sql上用到的参数要一样

  • 条件三:分页参数要一样 

  • 条件四:sql语句的文本要一样

  • 条件五:数据库连接的environment要一样

生命周期

  • 产生:sqlSession执行查询方法,而不是update等

  • 销毁:sqlSession关闭、sqlSession提交、sqlSession回滚、sqlSession执行update(新增、删除、更新)后底层会执行清除、主动清除

  • 辟谣:Mybatis 一级缓存脏读(数据被另外事务修改并提交后,仍会从缓存中读到旧数据(错误),实际是避免了事务不可重复读问题), Mybatis 一级缓存是在事务的生命周期之内的,在关闭session、执行commit、执行rollback都会清空Mybatis一级缓存。 实际上Mybatis 一级缓存反而避免了数据库事务中的脏读(读未提交)、不可重复读(读提交)问题。

源码解读

  • 代理模式与装饰模式的区别:代理模式在无参构造方法中确定地new了一个被代理的对象,编译时已经可以确定;而装饰模式是通过有参构造方法将被装饰对象传入装饰 类中,能够在运行时递归地被构造。

设计理念:在一个session内,不过期、不更新、不限制;

与spring整合时,如果开启了事务,事务内,Spring通过ThreadLocal始终使用同一个sqlSession,一级缓存生效; 如果没有开启事务,每次查询前会创建一个sqlSession,查询结束后会关闭sqlSession,所以一级缓存无效; 

二级缓存特点(跨sqlSession、有脏读问题,建议直接不用)

  1. 启用步骤:

  • 在mybatis.xml中settings标签下添加; 

  • 在mapper.xml中mapper标签下添加:属性eviction(LRU( 默认)、FIFO、SOFT、WEAK)和size(实例数,默认不限制),通过这两个属性可自定义二级缓存的清除策略

  • 在mapper.xml中mapper标签下添加:属性type,通过设置type可以指定使用的Cache对象,后面自定义缓存中有用到

  • 默认地,select标签flushCache="false" useCache="true",其他标签flushCache="true" entity类实现Serializable标记类; 

命中原则,同一SqlSessionFactory内,以下5个条件组成key,放入缓存中: 

  • 条件一:statementId相同 

  • 条件二:sql上用到的参数要一样 

  • 条件三:分页参数要一样 

  • 条件四:sql语句的文本要一样 

  • 条件五:数据库连接的environment一样 

生命周期 

  • sqlSession关闭-创建二级缓存、 

  • sqlSession提交-创建二级缓存、

  • sqlSession回滚、

  • sqlSession执行update(新增、删除、更新)、销毁二级缓存唯方法:同一mapper.xml执行update(新增、删除、更新)注意:同一个表的操作要放在同一个mapper下

  • sqlSession主动清除

  • 产生:1.能产生一级缓存;2.对sqlSession进行关闭或提交; 

  • 销毁:

源码解读 (MapperBuilderAssistant.class->useNewCache、XMLMapperBuilder.class->cacheElement)

  • 缓存是存在Configuration下并且缓存使用的是PerpetualCache(非分布式),而Configuration又是在DefaultSqlSessionFactory下,所以不同的SqlSessionFactory下的缓存是相互隔离的;

  • 通过自定义Redis缓存(实现Cache),将mapper下的cache指定type为自定义的类,就可以实现缓跨DefaultSqlSessionFactory;


1 回复 有任何疑惑可以回复我~

第一次查询的session要提交或关闭才会把数据写入。可以看TransactionalCache类的实现


1 回复 有任何疑惑可以回复我~

存一份就好了,为啥要存两份呢?不就冗余了吗

0 回复 有任何疑惑可以回复我~

举报

0/150
提交
取消

二级缓存的过程

我要回答 关注问题
意见反馈 帮助中心 APP下载
官方微信