一级缓存
- 基础
默认情况下,mybatis会启用一级缓存。如果使用同一个SqlSession对象调用了相同的SELECT语 句,则直接会从缓存中返回结果,而不是再查询一次数据库。
注意:SqlSession对象调用commit或close方法后,这个SqlSession中的一级缓存就会被清空;
2.测试
测试代码:
@Test
public void selectTest() {
SqlSession session = SqlSessionUtil.openSession(true);
TeacherMapper mapper = session.getMapper(TeacherMapper.class);
System.out.println(mapper.selectById(2));
System.out.println(mapper.selectById(2));
System.out.println(mapper.selectById(2));
}
运行结果:
可以看出只提交了一次事务,是同一个sqlsession。
可以想到:如果期间有其他sqlsession修改了数据库的数据,这个session就不会更新数据,容易脏读.
3.总结
- MyBatis一级缓存的生命周期和SqlSession一致。
- MyBatis一级缓存内部设计简单,只是一个没有容量限定的HashMap,在缓存的功能性上有所欠缺。
- MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据。
- SqlSession对象调用commit或close方法后,这个SqlSession中的一级缓存就会被清空;
二级缓存
-
手动开启详解及注意事项
- 在mybatis-config.xml 文件中保证设置中是缓存功能是开启的,默认就是开启的true。
- 在需要二级缓存的xml映射文件中,手动开启缓存功能,在根元素中加入一个标签即可。
- @CacheNamespace(blocking = true) 注解也可以实现二级缓存。
- 一个session查询完数据之后,需要调用commit或者close方法后,这个数据才会进入到二级缓存中,然后其他session就可以共享到这个缓存数据了。
- 注意:默认情况下,被二级缓存保存的对象需要实现序列化接口。
- 在默认的设置中SELECT语句不会刷新缓存,insert/update/delte会刷新缓存。
- cathe的参数属性
• type:cache使用的类型,默认是PerpetualCache,这在一级缓存中提到过。
• eviction: 定义回收的策略,常见的有FIFO,LRU。
• flushInterval: 配置一定时间自动刷新缓存,单位是毫秒。
• size: 最多缓存对象的个数。
• readOnly: 是否只读,若配置可读写,则需要对应的实体类能够序列化。
•blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。
- 在mybatis-config.xml 文件中保证设置中是缓存功能是开启的,默认就是开启的true。
-
测试
测试代码
@Test
public void selectTest1() {
SqlSession session1 = SqlSessionUtil.openSession();
TeacherMapper mapper1 = session1.getMapper(TeacherMapper.class);
System.out.println("one: "+mapper1.select(2));
session1.commit();
SqlSession session2 = SqlSessionUtil.openSession();
TeacherMapper mapper2 = session2.getMapper(TeacherMapper.class);
System.out.println("two: "+mapper2.select(2));
}
测试结果
可以看出,不同的sqlsession也可以共享缓存,只执行一条sql语句。
但是
使用MyBatis二级缓存有一个前提:必须保证所有的增删改查都在同一个命名空间下才行。