六、MyBatis 缓存机制
MyBatis 包含一个非常强大的查询缓存特性,它可以非 常方便地配置和定制。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存。
一级缓存和二级缓存。
- 1、默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
- 2、二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
- 3、为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存。
6.1、一级缓存
一级缓存(local cache), 即本地缓存, 作用域默认 为sqlSession。当 Session flush 或 close 后, 该 Session 中的所有 Cache 将被清空。
本地缓存不能被关闭, 但可以调用 clearCache() 来清空本地缓存, 或者改变缓存的作用域。
在mybatis3.1之后, 可以配置本地缓存的作用域. 在 mybatis.xml 中配置。
一级缓存演示&失效情况
同一次会话期间只要查询过的数据都会保存在当前SqlSession的一个Map中。
key:hashCode+查询的SqlId+编写的sql查询语句+参数。
一级缓存失效的四种情况:
1、不同的SqlSession对应不同的一级缓存
2、同一个SqlSession但是查询条件不同
3、同一个SqlSession两次查询期间执行了任何一次增 删改操作
4、同一个SqlSession两次查询期间手动清空了缓存
缓存数据:
@Test
public void testFirstLevelCache() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println(emp01);
//xxxxx
//1、sqlSession不同。
//SqlSession openSession2 = sqlSessionFactory.openSession();
//EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
//2、sqlSession相同,查询条件不同
//3、sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
//mapper.addEmp(new Employee(null, "testCache", "cache", "1"));
//System.out.println("数据添加成功");
//4、sqlSession相同,手动清除了一级缓存(缓存清空)
//openSession.clearCache();
Employee emp02 = mapper.getEmpById(1);
//Employee emp03 = mapper.getEmpById(3);
System.out.println(emp02);
//System.out.println(emp03);
System.out.println(emp01==emp02);
//openSession2.close();
}finally{
openSession.close();
}
}
6.2、二级缓存
二级缓存(second level cache),全局作用域缓存。
二级缓存默认不开启,需要手动配置。
MyBatis提供二级缓存的接口以及实现,缓存实现要求 POJO实现Serializable接口。
二级缓存在 SqlSession 关闭或提交之后才会生效。
6.2.1、使用步骤:
1、全局配置文件中开启二级缓存
<setting name= "cacheEnabled" value="true"/>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="jdbcTypeForNull" value="NULL"/>
<!--显式的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题 -->
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
2、需要使用二级缓存的映射文件处使用cache配置缓存
3、注意:POJO需要实现Serializable接口。
6.2.2、缓存相关属性:
- eviction:缓存的回收策略:
LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。
- flushInterval:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新 - size:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出 - readOnly:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象 不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些, 但是安全,因此默认是false。 - type="":指定自定义缓存的全类名;实现Cache接口即可;
6.2.3、缓存相关设置
- 1、全局setting的cacheEnable:
配置二级缓存的开关。一级缓存一直是打开的。 - 2、select标签的useCache属性:
配置这个select是否使用二级缓存。一级缓存一直是使用的。 - 3、sql标签的flushCache属性:
增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。 查询默认flushCache=false。 - 4、sqlSession.clearCache():
只是用来清除一级缓存。 - 5、当在某一个作用域 (一级缓存Session/二级缓存 Namespaces) 进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
6.2.4、测试代码
@Test
public void testSecondLevelCache() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
SqlSession openSession2 = sqlSessionFactory.openSession();
try{
//1、
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println(emp01);
openSession.close();
//第二次查询是从二级缓存中拿到的数据,并没有发送新的sql
// mapper2.addEmp(new Employee(null, "aaa", "nnn", "0")); //增删改清除缓存
Employee emp02 = mapper2.getEmpById(1);
System.out.println(emp02);
openSession2.close();
}finally{
}
}
如下:
6.3、第三方缓存整合
EhCache 是一个纯Java的进程内缓存框架,具有快速、精 干等特点,是Hibernate中默认的CacheProvider。
MyBatis定义了Cache接口方便我们进行自定义扩展。
步骤:
- 1、导入ehcache包,以及整合包,日志包
ehcache-core-2.6.8.jar、mybatis-ehcache-1.0.3.jar
slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.2.jar - 2、编写ehcache.xml配置文件
- 3、配置cache标签(在映射文件中)
<cache type= "org.mybatis.caches.ehcache.EhcacheCache"></cache>
参照缓存:若想在命名空间中共享相同的缓存配置和实例。 可以使用 cache-ref 元素来引用另外一个缓存。
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
<cache-ref namespace="com.atguigu.mybatis.dao.EmployeeMapper"/>
访问过程:
评论