1. Mybatis缓存机制
如果两次(或者多次)执行的查询SQL相同,每次都要从磁盘中去读数据,速度是受磁盘IO的限制.
如果加入缓存,相同的sql只有第一次需要从磁盘中查询数据,并且把数据缓存到内存中,那么从第二次查询开始,程序就可以直接从内存中快速的拿到数据
1.1 一级缓存
一级缓存 默认开启 ,作用范围是当前的 sqlSession ,又被称为 本地缓存
SqlSession sqlSession1 = null;
try {
sqlSession1 = MybatisUtil.createSession();
Student2 student1 = (Student2)
sqlSession1.selectOne("student2.selectStudentById", 1);
Student2 student2 = (Student2)
sqlSession1.selectOne("student2.selectStudentById", 1);
System.out.println(student1.hashCode()+":"+student2.hashCode());
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
}
1.2 二级缓存
@Test
public void testSelectById() {
SqlSession sqlSession1 = null;
try {
sqlSession1 = MybatisUtil.createSession();
Student2 student1 = (Student2)
sqlSession1.selectOne("student2.selectStudentById", 1);
Student2 student2 = (Student2)
sqlSession1.selectOne("student2.selectStudentById", 1);
System.out.println(student1.hashCode()+":"+student2.hashCode());
System.out.println(student1);
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession1);
}
SqlSession sqlSession2 = null;
try {
sqlSession2 = MybatisUtil.createSession();
Student2 student3 = (Student2)
sqlSession2.selectOne("student2.selectStudentById", 1);
student3.setName("cache被更改了");
Student2 student4 = (Student2)
sqlSession2.selectOne("student2.selectStudentById", 1);
System.out.println(student3.hashCode()+":"+student4.hashCode());
System.out.println(student3);
System.out.println(student4);
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtil.closeSession(sqlSession2);
}
}
<!-- 开启二级缓存 -->
<!--
1.eviction:指定内存的淘汰/回收策略
LRU(Least Recently Used 默认) – 最近最少使用:移除最长时间不被使用的对象。比较符合我们的预期的,因为缓存就是希望保留热点数据,淘汰非热点数据
FIFO(First In First Out) – 先进先出:类似于队列,按对象进入缓存的顺序来移除它们。
SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。比软引用更弱
2. flushInterval:刷新间隔,单位是毫秒.默认是不刷新
3. size:缓存的数量的上限,默认值是1024.超过就会触发淘汰策略
4. readOnly:只读,默认是false(可读可写)
-false的情况,缓存的对象必须要实现序列化接口,这是因为拿到的缓存对象不是原本缓存的对象,是因为在false的情况下,Mybatis对缓存的对象进行了拷贝,拷贝需要序列化,这样的情况,因为涉及到序列化的操作,所以效率会更慢一些,但是更安全
-true代表只读,就是拿到的缓存对象就是原本缓存的那个对象
-->
<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="false"/>
额外补充:
二级缓存的size,按照数量进行缓存,但是会将一个列表的对象只占用1个数量,所以一般不会对列表数据的查询结果进行缓存,可以通过两种方式解决该问题:
<select/>
标签的useCache
属性,将它设置为false
(默认为true)将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素
为 true。<select/>
标签的flushCache
属性,对于<select/>
标签而言默认为false
,对于<insert/>,<update/>,<delete/>
而言 flushCache 默认为true
将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空