1.一级缓存。
- 一级缓存默认会启用,想要关闭一级缓存可以在select标签上配置flushCache="true"。
- 一级缓存存在于SqlSession的生命周期中,在同一个SqlSession中查询时,Mybatis会把执行的方法和参数通过算法生成缓存的健值,将健值和查询结果存入一个Map对象中。如果同一个SqlSession中执行的方法和参数完全一致,那么通过算法会生成相同的健值,当Map缓存对象中已经存在该健值时,则会返回缓存中的对象
- 任何insert/ update/ delete操作都会清空一级缓存
@Test
public void Test1LevelCache(){
SqlSession session1 = sqlSessionFactory.openSession();
TUserMapper userMapper1 = session1.getMapper(TUserMapper.class);
String email = "qq.com";
Byte sex = 1;
List<TUser> list1 = userMapper1.selectByEmailAndSex2(email, sex);
System.out.println(list1.size());
//增删改操作会清空一级缓存和二级缓存
// TUser userInsert = new TUser();
// userInsert.setUserName("test1");
// userInsert.setRealName("realname1");
// userInsert.setEmail("myemail1");
// userMapper1.insert1(userInsert);
//会走缓存
List<TUser> list2 = userMapper1.selectByEmailAndSex2(email, sex);
System.out.println(list2.toString());
HashMap<String, Object> map = new HashMap<>();
map.put("email", email);
map.put("sex", sex);
//会走数据库
List<TUser> list3 = userMapper1.selectByEmailAndSex1(map);
System.out.println(list3.toString());
session1.close();
//会走数据库
SqlSession session2 = sqlSessionFactory.openSession();
TUserMapper userMapper2 = session2.getMapper(TUserMapper.class);
List<TUser> list4 = userMapper2.selectByEmailAndSex2(email, sex);
System.out.println(list2.toString());
session1.close();
}
2.二级缓存
- 二级缓存存在于SqlSessionFactory的生命周期中,可以理解为跨SqlSession,缓存是以namespace为单位的,不同namespace下的操作互不影响
- setting参数cacheEnabled是二级缓存的全局开关,默认值是true,若设为false,即使后面有二级缓存设置,也不会生效
- 要开启二级缓存,需要在SQL映射文件中添加配置
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
上述配置的意思是:
1)映射语句文件中的所有select语句将会被缓存
2)映射语句文件中的所有insert/ update/ delete语句会刷新缓存
3)缓存使用FIFO算法来回收,还有LRU等算法
4)根据时间表flushInterval来刷新缓存
5)缓存会存储列表集合或对象(无论查询方法返回什么)的512个引用
6)缓存会被视为是只读的缓存
@Test
public void Test2LevelCache(){
SqlSession session1 = sqlSessionFactory.openSession();
TUserMapper userMapper1 = session1.getMapper(TUserMapper.class);
String email = "qq.com";
Byte sex = 1;
List<TUser> list1 = userMapper1.selectByEmailAndSex2(email, sex);
System.out.println(list1.size());
// TUser userInsert = new TUser();
// userInsert.setUserName("test1");
// userInsert.setRealName("realname1");
// userInsert.setEmail("myemail1");
// userMapper1.insert1(userInsert);
//命中二级缓存
List<TUser> list2 = userMapper1.selectByEmailAndSex2(email, sex);
System.out.println(list2.toString());
session1.close();
//命中二级缓存
SqlSession session2 = sqlSessionFactory.openSession();
TUserMapper userMapper2 = session2.getMapper(TUserMapper.class);
List<TUser> list3 = userMapper2.selectByEmailAndSex2(email, sex);
System.out.println(list3.toString());
session2.close();
// 缓存是以namespace为单位的,会走数据库
SqlSession session3 = sqlSessionFactory.openSession();
TJobHistoryMapper userMapper3 = session3.getMapper(TJobHistoryMapper.class);
List<TUser> list4 = userMapper3.selectByEmailAndSex2(email, sex);
System.out.println(list4.toString());
session3.close();
}
Tips:使用二级缓存容易出现脏读,建议避免使用二级缓存,在业务层使用可控制的缓存代替更好。

参考
- 1)享学课堂Lison老师笔记