=========================
MyBatis缓存机制之二级缓存
=========================
与由SqlSession维护的一级即会话级缓存不同:
- 二级缓存由SqlSessionFactory维护,称为会话工厂级缓存;
- SqlSessionFactory本身就是一个单例,一个进程只有一个;
- 多个服务(Service)线程共享同一个二级缓存。
_线程_ _线程_
/ \ / \
Service1 Service2 SqlSessionFactory Database
空 20
20 <----------- 20 <- 20
20 <- 20 20
21 -----------> 空 -> 21
21 <- 21 <- 21
\_________ ___________/
\ /
一致
二级缓存具有如下特性:
- 二级缓存默认关闭,需要在mybatis-config.xml文件的settings标签中手动开启
...
...
- 需要在Mapper文件中通过cache标签设置二级缓存,该标签包含如下属性:
- eviction:清除策略
- LRU(默认):优先清除闲置时间最长的对象
- FIFO:按进入缓存的顺序清除缓存中的对象
- SOFT:基于垃圾回收器状态和软引用规则清除对象
- WEAK:基于垃圾回收器状态和弱引用规则清除对象
- flushInterval:刷新间隔毫秒值,不设置(默认)表示仅在调用语句时刷新
- size:最多缓存对象或列表的引用数,默认1024
- readOnly:缓存中的对象是否只读
- true:只读,得到的是缓冲中对象的引用,速度快
- false(默认):可写,得到的是缓存中将对象的拷贝,慢但是安全
- 二级缓存只能缓存实现了序列化接口的实体类对象
1 开启二级缓存
在mybatis-config.xml文件中添加:
...
...
2 设置二级缓存
在MemberMapper.xml文件中添加:
...
...
3 实现序列化接口
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Member implements Serializable {
...
}
4 编写测试用例
public class MemberDaoTest {
...
@Test
public void testSearchById() {
Member member;
SqlSession session1 = MyBatisUtil.getFactory().openSession();
MemberDao dao1 = session1.getMapper(MemberDao.class);
System.out.println("\n第一次查询...");
System.out.println(member = dao1.searchById(1));
session1.commit(); // 这里必须提交!
SqlSession session2 = MyBatisUtil.getFactory().openSession();
MemberDao dao2 = session2.getMapper(MemberDao.class);
System.out.println("\n第二次查询...");
System.out.println(dao2.searchById(1));
dao1.modifyAge(member.getId(), member.getAge() + 1);
session1.commit();
System.out.println("\n第三次查询...");
System.out.println(dao2.searchById(1));
}
...
}
运行测试用例:
第一次查询...
[main] DEBUG - ==> Preparing: select id, nick, gender, age, city from t_member where id = ? sg :==> Preparing: select id, nick, gender, age, city from t_member where id = ?
[main] DEBUG - ==> Parameters: 1(Integer)sg :==> Parameters: 1(Integer)
[main] DEBUG - <== Total: 1sg :<== Total: 1
Member(id=1, nick=john, gender=男, age=20, city=北京)
第二次查询...
Member(id=1, nick=john, gender=男, age=20, city=北京)
第三次查询...
[main] DEBUG - ==> Preparing: select id, nick, gender, age, city from t_member where id = ? sg :==> Preparing: select id, nick, gender, age, city from t_member where id = ?
[main] DEBUG - ==> Parameters: 1(Integer)sg :==> Parameters: 1(Integer)
[main] DEBUG - <== Total: 1sg :<== Total: 1
Member(id=1, nick=john, gender=男, age=21, city=北京)
例程:Dynamic
在Mapper文件中:
- select标签的useCache属性控制该查询是否使用缓存,默认为true
- update标签的flushCache属性控制该更新是否清除缓存,默认为true