目录
详解https://www.yisu.com/zixun/204042.html
3.缓存
3.1简介
1)MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。
2)MyBatis系统中默认定义了两级缓存。
- 一级缓存:SqlSession级别的缓存,缓存的数据只在SqlSession内有效
- 二级缓存:mapper级别的缓存,同一个namespace公用这一个缓存,所以对SqlSession是共享的
3)默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
4)二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
5)为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存。
3.2一级缓存
一级缓存是基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空。
一级缓存是SqlSession级别的缓存,在操作数据库的时候需要先创建SqlSession会话对象,在对象中有一个HashMap用于存储缓存数据,此HashMap是当前会话对象私有的,别的SqlSession会话对象无法访问。
- key : hashCode + 查询的SqlId + 编写的sql查询语句 + 参数
一级缓存是基于SQLSession的缓存,一级缓存的内容不能跨SQLSession。由mybatis自动维护。不同的sqlsession之间的缓存区域是互相不影响的。
本地缓存不能被关闭,但可以调用clearCache()来清空本地缓存,或者改变缓存的作用域。
具体流程:
- 第一次执行select完毕会将查到的数据写入SqlSession内的HashMap中缓存起来
- 第二次执行select会从缓存中查数据,如果select相同且传参数一样,那么就能从缓存中返回数据,不用去数据库了,从而提高了效率
注意事项:
- mybatis默认是开启一级缓存,不需要配置
- 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中的所有缓存数据,这样可以保证缓存中存的数据永远和数据库中一致,避免出现脏读
- 一个SqlSession结束后那么它里面的一级缓存也就不存在了。
- mybatis的缓存是基于[namespace:sql语句:参数]来进行缓存的。意思就是,SqlSession的HashMap存储缓存数据时,是使用[namespace:sql:参数]作为key,查询返回的语句作为value保存的。
一级缓存失效的几种情况
1)不同的SqlSession对应不同的一级缓存。
2)同一个SqlSession但是查询条件不同。
3)同一个SqlSession两次查询期间执行了任何一次增删改操作。
4)同一个SqlSession两次查询期间手动清空了缓存。
3.3二级缓存
mybatis中二级缓存是mapper级别的缓存,默认是关闭的。
对于一个mapper下的不同的SQLSession可以共享二级缓存。
不同的mapper是相互隔离的。
二级缓存的特点是需要打开二级缓存的配置,并且需要映射的java类需要实现序列化。
二级缓存原理:
二级缓存和一级缓存的区别:
二级缓存范围更大,多个SQLSession可以共享一个mapper级别的二级缓存,数据类型依然是HashMap来存储二级缓存内容,mapper是按照namespace划分,如果namespace相同则使用同一个二级缓存,
一级缓存范围会更小,是一个SQLSession级别。
二级缓存使用步骤
第一步:在mybatis的全局配置文件中开启二级缓存:
<settings>
<!--cacheEnabled:开启mybatis的二级缓存-->
<setting name="cacheEnabled" value=" true"/>
</settings>
第二步:将映射的pojo类实现序列化:
public class Student implements Serializable
第三步:在mapper配置文件中使用cache标签:
<!--
cache和二级缓存相关标签
eviction属性:代表缓存的回收策略,mybatis提供了回收策略如下:
LRU:最近最少使用,对于最长时间不用的对象进行回收
FIFO:先进先出,按照帝乡进入缓存的顺序来进行回收
SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
WEAK:弱引用,基于垃圾回收器状态和弱引用规则的对象
flushInterval属性:刷新间隔时间,单位是毫秒
size属性:引用数目,代表缓存可以存储最多多少个对象
readOnly属性:true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一点,但是安全,因此默认是false。
-->
<cache eviction="FIFO" flushInterval="1000" size="1024" readOnly="false"/>
注:对于访问多的查询请求并且用户对查询结果实时性要求不高的情况下,可采用mybatis二级缓存,降低数据库访问量,提高访问速度。
若想禁用当前select语句的二级缓存,添加useCache=“false”(默认情况下为true)就可以了:<select id="getUserById" parameterType="int" resultType="user" useCache="false">
useCache=“true” 缓存的使用和禁止
flushCache=“true” 刷新缓存
具体流程:
- 当一个sqlseesion执行了一次select后,关闭此session或者commit的时候,会将查询结果缓存到二级缓存
- 当另一个sqlsession执行select时,首先会在他自己的一级缓存中找,如果没找到,就回去二级缓存中找,找到了就返回,就不用去数据库了,从而减少了数据库压力提高了性能
注意事项:
- 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前mapper缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读
- mybatis的缓存是基于[namespace:sql语句:参数]来进行缓存的,意思就是,SqlSession的HashMap存储缓存数据时,是使用[namespace:sql:参数]作为key,查询返回的语句作为value保存的。
测试:
//二级缓存的测试
@Test
public void testCache2() {
//不同的SQLSession会话进行相同的SQL查询操作
//SQLSession1实例
SqlSession sqlSession = sessionFactory.openSession();
Student23Mapper student23Mapper = sqlSession.getMapper(Student23Mapper.class);
//SQLSession2实例
SqlSession sqlSession1 = sessionFactory.openSession();
Student23Mapper student23Mapper1 = sqlSession1.getMapper(Student23Mapper.class);
//sqlsession实例3
SqlSession sqlSession2 = sessionFactory.openSession();
Student23Mapper student23Mapper2 = sqlSession2.getMapper(Student23Mapper.class);
//第一次查询id为1的用户
Student23 student23 = student23Mapper.selectStudentByUid(1L);
System.out.println(student23);
//这里执行关闭操作,将SQLSession中的数据写入到二级缓存区域
sqlSession.close();
//第二次查询id为1的用户
Student23 student24 = student23Mapper1.selectStudentByUid(1L);
System.out.println(student24);
sqlSession1.close();
}