专注Java领域技术
我们一直在努力

07. Mybatis 缓存-二级缓存

原文始发于:07. Mybatis 缓存-二级缓存

Mybatis 除了一级缓存外, 还支持二级缓存, 二级缓存是namespace级别的.

1. 二级缓存

1.1 二级缓存特点

  • 二级缓存是namespace 级别的, 凌驾于sqlSession 之上, 可实现sqlSession 之间的共享
  • 二级缓存全局配置模式是开启的, 可进行关闭
  • 二级缓存是事务性的, 当sqlSession正常关闭或提交事务时, 会将sqlSession中的一级缓存刷新到二级缓存中
  • 当事务发生回滚时, sqlSession中的一级缓存不会刷新到二级缓存中.

1.2 开启二级缓存

  • 开启缓存的最简单的方式, 就是直接在sql映射文件中,添加标签即可.
  • 需要注意的是, 需要缓存的实体需要实现序列化接口
<cache/> 

1.3 cache 标签默认行为

使用其默认配置. 默认的缓存特点:

  • 映射语句文件中的所有 select 语句的结果将会被缓存。可通过设置useCache=false 来关闭select语句的缓存
  • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
  • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
  • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
  • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
  • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
<cache/> 

1.4 cache 标签属性

cache 标签提供了四个属性来自定义默认二级缓存的行为:

  • flushInterval: 设置刷新间隔, 即请空缓存的时间, 单位毫秒. 默认不情况, 当在调用语句时刷新
  • size: 设置每个namespace最多缓存对象的引用个数, 默认为1024.
  • readOnly: 设置得到的缓存是否只读.
    • true: 设置只读, 会返回给缓存的引用, 速度会很快. 但不安全,因为可以修改
    • false: 设置读写, 会通过反序列化技术生成新的对象, 效率会稍微慢一点儿
  • eviction: 设置缓存清除策略, 默认为LRU.
    • LRU: 最近最少使用:移除最长时间不被使用的对象。
    • FIFO: 先进先出:按对象进入缓存的顺序来移除它们。
    • SOFT: 软引用:基于垃圾回收器状态和软引用规则移除对象。
    • WEAK: 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

2. 二级缓存测试

2.1 设置全局开启二级缓存

全局二级缓存是默认开启的, 或者显示声明开启全局二级缓存.

<settings>  <setting name="cacheEnabled" value="true" /> </settings> 

2.2 需要缓存的实体实现序列化接口

由于缓存需要序列化实体, 所以实体必须实现序列化接口.

public class EmployeePO implements Serializable {      private static final long serialVersionUID = -2164461308545729638L;          //... } 

2.3 测试用例

  • 测试二级缓存生效: sqlSession 关闭时, 将本sqlSession中的一级缓存写入二级缓存中
  • 测试二级缓存生效: sqlSession 提交事务时, 将本sqlSession中的一级缓存写入二级缓存中
  • 测试二级缓存不生效: 如果查询中设置useCache=false, 二级缓存不生效
  • 测试二级缓存不生效: sqlSession 回滚事务时, 不会将sqlSession中的缓存写入二级缓存中
public class TestCacheLevel2 {       // 测试二级缓存生效: sqlSession 关闭时, 将本sqlSession中的一级缓存写入二级缓存中     @Test     public void test_valid1(){          SqlSession sqlSession1 = SqlSessionUtil.openSession(false);         SqlSession sqlSession2 = SqlSessionUtil.openSession(false);          EmployeeMapper empMapper1 = sqlSession1.getMapper(EmployeeMapper.class);         EmployeeMapper empMapper2 = sqlSession2.getMapper(EmployeeMapper.class);          System.out.println("进行第一次查询...");         EmployeePO emp1 = empMapper1.findById(1L);          // sqlSession 关闭时, 将一级缓存写入二级缓存.         sqlSession1.close();          System.out.println("进行第二次查询...");         EmployeePO emp2 = empMapper2.findById(1L);          Assert.assertNotEquals(emp1, emp2);     }      // 测试二级缓存生效: sqlSession 提交事务时, 将本sqlSession中的一级缓存写入二级缓存中     @Test     public void test_valid2(){          SqlSession sqlSession1 = SqlSessionUtil.openSession(false);         SqlSession sqlSession2 = SqlSessionUtil.openSession(false);          EmployeeMapper empMapper1 = sqlSession1.getMapper(EmployeeMapper.class);         EmployeeMapper empMapper2 = sqlSession2.getMapper(EmployeeMapper.class);          System.out.println("进行第一次查询...");         EmployeePO emp1 = empMapper1.findById(1L);          // sqlSession 提交事务时, 将本sqlSession中的数据写入缓存中         sqlSession1.commit();          System.out.println("进行第二次查询...");         EmployeePO emp2 = empMapper2.findById(1L);          Assert.assertNotEquals(emp1, emp2);     }      // 测试二级缓存不生效: 如果查询中设置useCache=false, 二级缓存不生效     @Test     public void test_invalid1(){          SqlSession sqlSession1 = SqlSessionUtil.openSession(false);         SqlSession sqlSession2 = SqlSessionUtil.openSession(false);          EmployeeMapper empMapper1 = sqlSession1.getMapper(EmployeeMapper.class);         EmployeeMapper empMapper2 = sqlSession2.getMapper(EmployeeMapper.class);          System.out.println("进行第一次查询...");         EmployeePO emp1 = empMapper1.findById(1L);          // sqlSession 关闭时, 将一级缓存写入二级缓存.         sqlSession1.close();          System.out.println("进行第二次查询...");         EmployeePO emp2 = empMapper2.findById(1L);          Assert.assertNotEquals(emp1, emp2);     }      // 测试二级缓存不生效: sqlSession 回滚事务时, 不会将sqlSession中的缓存写入二级缓存中     @Test     public void test_invalid2(){          SqlSession sqlSession1 = SqlSessionUtil.openSession(true);         SqlSession sqlSession2 = SqlSessionUtil.openSession(true);          EmployeeMapper empMapper1 = sqlSession1.getMapper(EmployeeMapper.class);         EmployeeMapper empMapper2 = sqlSession2.getMapper(EmployeeMapper.class);          System.out.println("进行第一次查询...");         EmployeePO emp1 = empMapper1.findById(1L);          // sqlSession 提交事务时, 将本sqlSession中的数据写入缓存中         sqlSession1.rollback();          System.out.println("进行第二次查询...");         EmployeePO emp2 = empMapper2.findById(1L);          Assert.assertNotEquals(emp1, emp2);     }  } 

赞(0) 打赏
未经允许不得转载:Java小咖秀 » 07. Mybatis 缓存-二级缓存
免责声明

抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

专注Java技术 100年

联系我们联系我们

你默默的关注就是最好的打赏~

支付宝扫一扫打赏

微信扫一扫打赏