04_Mybatis_缓存
缓存_缓存介绍
-
MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便的配置和定制。缓存可以极大的提升查询效率
-
MyBatis系统中 默认定义了两级缓存
-
一级缓存和二级缓存
- 1、默认情况下:只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启;
- 2、二级缓存需要手动开启和配置,他是基于namespace级别的缓存
- 3、为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
缓存_一级缓存体验
两级缓存
一级缓存:(本地缓存)sqlSession级别的缓存。一级缓存是一直开启的;SqlSession级别的Map
与数据库同一次会话期间查询到的数据会放在本地缓存中。
如果再次获取相同的数据,直接从缓存中拿。
二级缓存:(全局缓存)
缓存_一级缓存失效的四种情况
一级缓存失效情况(没有使用到当前一级缓存的情况,效果就是,还要再次向数据库发送sql)
1、sqlSession不同
2、sqlSession相同,查询条件不同
3、sqlSession相同,两次查询之间执行增删改操作(这次增删改操作可能影响当前数据)
4、sqlSession相同,手动清除一级缓存(缓存情况)openSession.clearCache();
@Test
public void testFirstLevelCache() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try {
//一级缓存初体验
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee empById01 = mapper.getEmpById(1);
System.out.println(empById01);
//1、sqlSession不同。
/*SqlSession openSession2 = sqlSessionFactory.openSession();
EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);*/
//3、sqlSession相同,两次查询之间执行了增删改操作;(增删改操作有可能影响当前数据)
/*mapper.addEmp(new Employee(null,"cache","1","testCache@qq.com"));
System.out.println("数据添加成功");*/
//4、sqlSession相同,手动清空一级缓存
// openSession.clearCache();
//2、sqlSession相同,查询条件不同
Employee empById02 = mapper.getEmpById(1);
System.out.println(empById02);
System.out.println(empById01 == empById02);
// openSession2.close();
} finally {
openSession.close();
}
}
缓存_二级缓存使用&细节
1、开启全局二级缓存配置
<setting name="cacheEnabled" value="true"></setting>
2、去mapper.xml中配置使用二级缓存
<cache eviction="" flushInterval="" readOnly="" size="" type=""></cache>
<!--
eviction:缓存回收策略
· LRU:最近使用最少的,移除最长时间不被使用的对象
· FIFO:先进先出,按对象进入缓存的顺序来移除
· SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
· WEAK:弱引用,更积极的移除垃圾回收器状态和弱引用规则的对象
· 默认是LRU
flushInterval:刷新间隔,单位毫秒
· 默认情况下是不设置,没有刷新时间,缓存仅仅调用语句时刷新
size:引用数目,正整数
· 代表缓存最大可以存储多少个对象,太大容易导致内存溢出
readOnly:只读,true/false
· true:只读缓存,会给所有调用者返回缓存对象的相同实例
1 false:读写缓存,会返回缓存对象的拷贝(通过序列化),
type:指定自定义缓存的全类名;
实现Cache接口即可
-->
/**
*两级缓存:
* 一级缓存(本地缓存):sqlSession级别的缓存,一级缓存是一直开启的,sqlSession级别的一个Map
* 与数据库同一次会话期间查询到的数据会放在本地缓存中。
*
* 一级缓存失效情况(没有使用到当前一级缓存的情况):
* 1、sqlSession不同。
* 2、sqlSession相同,查询条件不同(当前一级缓存中还没有这个数据)
* 3、sqlSession相同,两次查询之间执行了增删改操作;(增删改操作有可能影响当前数据)
* 4、sqlSession相同,手动清空一级缓存
*
* 二级缓存(全局缓存):基于namespace级别的缓存,一个namespace对应一个二级缓存;
* 工作机制:
* 1、一次会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中
* 2、如果会话关闭,一级缓存中的数据会被保存到二级缓存中。新的会话查询信息,就可以参照二级缓存
* 3、不同的namespace查出的数据会放在自己对应的缓存中(namespace级别的map)
*
* 查出的数据都会默认先放在一级缓存中,
* 只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存
* 使用&细节:
* 1)、开启全局二级缓存配置.<setting name="cacheEnabled" value="true"/>
* 2)、去mapper.xml中配置使用二级缓存;<cache></cache>
* 3)、POJO需要实现序列化接口
*/
@Test
public void testSecondLevelCache() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
SqlSession openSession2 = sqlSessionFactory.openSession();
try {
//
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println(emp01);
openSession.close();
//第二次查询是从二级缓存中拿到的数据
Employee emp02 = mapper2.getEmpById(1);
System.out.println(emp02);
openSession2.close();
} finally {
// openSession.close();
}
}
缓存_缓存有关的配置以及属性
/**
* 和缓存有关的设置/属性
* 1)、cacheEnabled=true,【false:关闭缓存(二级缓存关闭,不会关闭一级缓存)】
* 2)、每个select标签都有一个useCache标签,useCache="true"
* false:不使用缓存【一级缓存仍然可以使用,二级缓存不使用】
* 3)、每个增删改标签都有flushCache标签,flushCache="true"【一级二级都会清除】
* 增删改执行后就会清除缓存
* 测试:flushCache="true",一级缓存清空了,二级缓存也会被清除
* 查询标签也有flushCache="true"
* 如果设置为false,每次查询之后都会清空缓存,缓存不会被使用
* 4)、openSession.clearCache();只是清除当前session的一级缓存
* 5)、localCacheScope:本地缓存作用域(一级缓存SESSION),当前会话的所有数据保存在会话缓存中。
* 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。【禁用一级缓存】
* */
缓存_缓存原理图示


浙公网安备 33010602011771号