一、缓存机制介绍
1、缓存方式
Mybatis系统中默认定义了两级缓存:
分别是一级缓存和二级缓存
1、默认情况下只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
2、二级缓存需要手动开启和配置,它是记忆namespace级别的缓存。
3、为了提高扩展性,Mybatis定义了缓存接口Cache,我们可以通过实现Cache接口来自定义二级缓存。
2、一级缓存
- 与数据库同一次会话期间查询到的数据会放到本地缓存中。
- 以后如果要获取相同的数据,直接从缓存中拿,没必要再去数据库中去查了。
- 一级缓存失效情况:还需要再向数据库发出查询。
一级缓存失效情况如下:
1、SqlSession不同
2、SqlSession相同,查询条件不同(当前一级缓存中还没有这个数据)。
3、SqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前的数据有影响)
SqlSession相同,手动清除了一级缓存(缓存清空)
2、二级缓存
属于全局缓存,基于namespace名称空间级别的缓存,一个namespace对应一个二级缓存。
工作机制:
1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中。
2、如果会话关闭,一级缓存中的数据会保存到二级缓存中,新的会话查询信息,就可以参照二级缓存的内容。
3、不同namespace查出的数据会放在自己对应的缓存中(map)中。
4、只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中去
(1)、二级缓存的使用
第一步:开启全局二级缓存配置
<setting name="cacheEnabled" value="true" />
第二步:去mapper.xml中配置使用二级缓存
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024" type="">
</cache>
size:缓存存放多少元素
type: 指定自定义缓存的全类名----实现cache接口即可
参数解析:
第三步:POJO需要实现序列化接口
3、缓存的一些设置规则
cacheEnabled设置为false,关闭缓存,这时候关闭的是二级缓存,一级缓存不会被关闭。
- 每个select标签都有useCache="true"设置,设置为false:不使用缓存(关闭的是二级,一级正常用)。
- 每个增删改查标签的flushCache="true",表示增删改查执行完成后就会清空缓存(一级二级都会被清空).
sqlSession.clearCache();只清空当前session的一级缓存
4、缓存的原理图
5、缓存顺序
二级缓存---->一级缓存----->数据库
6、融入第三方缓存进来,只要实现cache接口就可以
第三方缓存比较主流是:EhCache,需要pom文件中引入EhCachejar包
<cache type="EhCache自定义类"></cache>
7、spring与mybatis整合后一级缓存失效问题解析
spring结合mybatis后,一级缓存作用:
在未开启事务的情况之下,每次查询,spring都会关闭旧的sqlSession而创建新的sqlSession,因此此时的一级缓存是不起作用的
在开启事务的情况之下,spring使用ThreadLocal获取当前资源绑定同一个sqlSession,因此此时一级缓存是有效的。
mybatis的一级缓存是基于session来的,当单独使用mybatis的时候,一级缓存是起作用的,在一个session中查询2遍同样的sql,只会打印一次sql语句。但当mybatis与spring搭配使用后,mybatis的一级缓存就会失效,会打印2次sql。
一级缓存失效原因:mybatis和spring结合使用的时候,将原本的DefaultSqlSession替换成了SqlSessionTemplate,并且在SqlSessionTemplate将sqlSession替换成了sqlSessionProxy代理对象,当我们执行sqlSession的方法的时会调用到SqlSessionInterceptor的invoke()方法, 在invoke()方法的fianlly中调用了SqlSessionUtils.closeSqlSession()方法将SqlSession关闭了,所以一级缓存就会失效了。
也就是说,spring对mybatis的SqlSession的使用是由SqlSessionTemplate控制的,在SqlSessionTemplate类中执行SQL语句的SqlSession都是通过sqlSessionProxy来代理执行的,sqlSessionProxy的生成是在构造函数中赋值