Mybatis缓存
本文,记录Mybatis缓存使用及原理
一级缓存
一级缓存是SqlSession级别的,默认开启,一个SqlSession,有一个一级缓存,各个SqlSession直接缓存不共享
SqlSession一级缓存使用
- 缓存
key
为statmentId,params,boundSql,rowwBounds
+environmentId
- 查询数据,
SqlSession
计算出key
,从BaseExecutor
持有的HashMap
中查找是否有结果,如果有则返回,如果没有进行下一步 SqlSession
查询数据库,计算出key
,存储到SqlSession
持有BaseExecutor
的HashMap
中,返回结果- 第二次查询,走第一步
一级缓存失效
- 由于不同SqlSession缓存不共享,如果跨SqlSession,缓存是失败的;
- 当Mybatis执行了
Insert,Update,Delete
,会将缓存全部clear
; - 手动
commit,rollback
,会将缓存全部clear
; - 当指定
LocalCacheScope
级别是STATEMENT
的时候,不保存SqlSession
缓存; SqlSession
是非线程安全的,对于临界状态的代码,需要手动保持线程安全;
注意
- 不要对Mybatis返回对象做任何修改:由于一级缓存的存在,Mybatis返回数据是缓存数据的引用,如果修改对象,会将缓存数据一起修改;
二级缓存
二级缓存,是Mapper级别的,需要手动开启,可以跨SqlSession读取,由于二级缓存可以自定义实现存储介质多样,需要将polo类实现序列化接口
二级缓存查询流程:
二级缓存存储流程:
- 当声明使用二级缓存时,Mybatis将使用
CachingExecutor
作为执行器,他持有的TransactionalCacheManager
来做二级缓存管理,当TransactionalCacheManager
调用commit
的时候会将数据存入二级缓存,而CachingExecutor
在close
,commit
的时候会调用TransactionalCacheManager.commit()
,然后SqlSession
的commit,close
实际就是调用Executor
的commit,close
,所以只有当SqlSession
调用commit,close
时,才会存入二级缓存; TransactionalCacheManager
中持有TransactionalCache
,每一个事物会有一个缓存,当查询时,如果没有缓存,会从数据库中查询数据,并放入TransactionalCache
持有的entriesToAddOnCommit
中,当commit
时,批量从entriesToAddOnCommit
刷入二级缓存
二级缓存使用
- 配置文件指定开启二级缓存
- Mapper添加二级缓存开启配置
- 注解:
@CacheNamespace
- XML:
<cache/>
- SQL级别指定是否使用缓存,刷新缓存
- useCache=“false”:是否使用缓存
- flushCache:当执行
insert,update,delete
是否删除缓存,默认ture - 注解使用
@Options
进行配饰
- 注解:
- 缓存对象实现序列化接口
注意
- 保证单表缓存必须在一个namespace下【只有单表操作上使用缓存】否则会导致数据脏读
- 确保,
select
操作远大于insert,update,delete
时使用
使用Redis实现二级缓存
使用Redis作为二级缓存,可以实现分布式缓存
- 指定缓存实现
- <cache type=“org.mybatis.caches.redis.RedisCache” />
- @CacheNamespace(implementation = RedisCache.class)
- 添加Redis配置文件
redis.properties
host=192.168.1.105 port=6379 connectionTimeout=5000 password= database=0
- 使用缓存