一、二级缓存简介
1、简介
2、说明
二级缓存是全局缓存,基于 namespace 级别的缓存,一个 namespace 对应一个二级缓存;
工作机制:
(1)一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
(2)如果当前会话关闭了,一级缓存中的数据会被保存到二级缓存中,新的会话查询信息,就可以参照二级缓存中的内容;
(3)每一个 namespace 对应一个二级缓存,不同 namespace 查出的数据会放在自己对应的缓存中(map)
sqlSession===EmployeeMapper==>Employee
DepartmentMapper==>Department
二、二级缓存的使用步骤
1、全局配置文件中开启二级缓存
<setting name = "cacheEnabled" value="true" /> 默认是 false(不开启)
2、在每个 mapper.xml 中配置使用二级缓存 <cache></cache>
二级缓存需要在 mapper.xml 中配置 <cache> 标签,所以二级缓存来说是 映射文件级别的。不管 SqlSession 是怎么创建的,只要是访问的同一个映射文件中的 SQL 语句,就可以被缓存。
3、注意: POJO 需要实现 Serializable 接口
三、二级缓存工作机制
工作机制:
1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
2、如果会话关闭:一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;
3、不同namespace查出的数据会放在自己对应的缓存中(map), 效果:数据会从二级缓存中获取,查出的数据都会被默认先放在一级缓存中。
4、只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中;
5、如果 sqlSession 没有关闭,还是会从一级缓存查询;
四、二级缓存相关的属性(<cache>标签中的属性)
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024" type=""></cache>
(1)cache 开启二级缓存
(2)eviction 缓存的回收策略
LRU:最近最少使用的,移除最长时间不被使用的对象。
FIFO:先进先出,按对象进入缓存的顺序来移除它们。
SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象。
VEAK:弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象。
默认的是 LRU。
(3)flushInterval 缓存刷新间隔,单位毫秒
缓存多长时间清空一次,默认不清空,设置一个毫秒值
(4)readOnly 是否只读 true/false
(5)size 缓存中存放多少元素,引用数据,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出,还严重消耗内存;太小则没意义;
(6)type:用来设置第三方缓存,指定自定义缓存的全类名;实现cache接口即可。
五、代码示例
1、使用二级缓存
代码:
/**
* 二级缓存
* @throws IOException
*/
@Test
public void testSecondLevelCache() throws IOException {
SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
try {
EmployeeMapperCache mapper = sqlSession.getMapper(EmployeeMapperCache.class);
EmployeeMapperCache mapper2 = sqlSession2.getMapper(EmployeeMapperCache.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println("emp01 = " + emp01);
sqlSession.close();
//第二次查询是从二级缓冲中拿到的数据,并没有发送新的SQL
//缓存命中率 Cache Hit Ratio [com.njf.mybatis.dao.EmployeeMapperCache]: 0.5
Employee emp02 = mapper2.getEmpById(1);
System.out.println("emp02 = " + emp02);
sqlSession2.close();
System.out.println(emp01 == emp02);
} finally {
sqlSession.close();
}
}
运行结果:
2、未开启二级缓存
代码:
/**
* 未启用二级缓存
* @throws IOException
*/
@Test
public void testSecondLevelCacheDisable() throws IOException {
SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
try {
DepartmentMapper mapper = sqlSession.getMapper(DepartmentMapper.class);
DepartmentMapper mapper2 = sqlSession2.getMapper(DepartmentMapper.class);
Department dept01 = mapper.getDeptById(1);
System.out.println("dept01 = " + dept01);
sqlSession.close();
Department dept02 = mapper2.getDeptById(1);
System.out.println("dept02 = " + dept02);
sqlSession2.close();
System.out.println(dept01 == dept02);
} finally {
sqlSession.close();
sqlSession2.close();
}
}
运行结果:
可以看到发送了两条SQL语句,正是因为没有使用二级缓存,当第一个 sqlSession 关闭后,没有把查询结果放在二级缓存中,所以再次查询时会重新发送 SQL 语句。