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

06. Mybatis 缓存-一级缓存

原文始发于:06. Mybatis 缓存-一级缓存

和其它ORM 框架类似, Mybatis也提供了一级缓存和二级缓存机制. 但是Mybatis 毕竟不是专业做缓存的, 提供的缓存实现比较简单, 所以Mybatis 提供了缓存的通用接口, 可以自己进行扩展.

1. 一级缓存

1.1 一级缓存特性

  • 一级缓存是sqlSession 级别的, 也称会话级别的. 也就是说, 一个sqlSession 拥有一个缓存Map对象.
  • 一级缓存默认开启, 而且不可全局禁用.
  • 同一个sqlSession 中, 对同一条件的查询
  • 一级缓存给的是对象的引用

1.2 一级缓存机制

  • 执行查询时, 先尝试从一级缓存中获取, 如果有则返回对象的引用地址; 如果没有则进行jdbc 查询
  • 执行jdbc查询后, 将jdbc 查询结果缓存到一级缓存中
  • 当此sqlSession 执行任意CRUD 操作时, 清空当前sqlSession 的所有缓存.

1.3 不使用一级缓存

  • 不同sqlSession 对相同po 进行相同条件查询时
  • 同一sqlSession, 两次相同条件查询之间, 显示调用了清理缓存方法sqlSession.clearCache();
  • 同一sqlSession, 两次相同条件查询之间, 执行了任意的增删改方法, 增删改方法会清理缓存
  • 同一sqlSession, 两次相同条件查询之间, 执行了任意表示flushCache=true 的查询
  • 对标识了flushCache=true 的查询, 不生效

1.4 禁止一级缓存

虽然一级缓存是不可禁止的, 只能通过在执行查询前, 显示或隐式执行sqlSession.clearCache()清理缓存, 以达到不使用一级缓存的效果

  • 显示清理缓存: 执行sqlSession.clearCache()方法
  • 隐式清理缓存:
    • 执行任意的增删改方法
    • 执行任意标识flushCache=true 的查询方法.

2. 一级缓存使用

观察缓存是否生效, 我们根据控制台是否输出第二次进行jdbc 查询的日志来判定

2.1 两次相同条件查询之间, 同一sqlSession 执行, 一级缓存生效

  • 观察日志输出, 第二次查询并没有发送sql
  • 观察日志输出, 两次查询到的emp1和emp2 引用完全相同, 属于同一个对象
@Test public void test(){      SqlSession sqlSession = SqlSessionUtil.openSession(false);      EmployeeMapper empMapper1 = sqlSession.getMapper(EmployeeMapper.class);     EmployeeMapper empMapper2 = sqlSession.getMapper(EmployeeMapper.class);      System.out.println("进行第一次查询...");     EmployeePO emp1 = empMapper1.findById(1L);      System.out.println("进行第二次查询...");     EmployeePO emp2 = empMapper2.findById(1L);      System.out.println("emp1:" + emp1);     System.out.println("emp2:" + emp2);      // 验证empMapper1与empMapper2不是一个对象, emp1 和 emp2 是同一个对象     Assert.assertNotEquals(empMapper1, empMapper2);     Assert.assertEquals(emp1, emp2); } 

2.2 两次相同条件查询之间, 不同的sqlSession 执行, 一级缓存失效

  • 使用不同的sqlSession 进行相同条件的两次查询, 不会使用一级缓存.
  • 观察日志, 第二次查询发送了查询sql, 且emp1 和 emp2 对象引用不同
// 测试一级缓存失效: 两次相同条件查询之间, 不同的sqlSession 执行 @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);      System.out.println("进行第二次查询...");     EmployeePO emp2 = empMapper2.findById(1L);      Assert.assertNotEquals(emp1, emp2); } 

2.3 两次相同条件查询之间, 执行了任意增删改操作, 一级缓存失效

  • sqlSession 执行任何的增删改操作之后, 都会将当前session的缓存map 清空.
  • 观察日志, 第二次查询发送了查询sql, 且emp1 和 emp2 对象引用不同
// 测试一级缓存失效: 两次相同条件查询之间, 执行了任意增删改操作 @Test public void test_invalid2(){      SqlSession sqlSession = SqlSessionUtil.openSession(false);      EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class);     PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);      System.out.println("进行第一次查询...");     EmployeePO emp1 = empMapper.findById(1L);      // 同一sqlSession 对其它对象做增删改操作     personMapper.delete(1); //        personMapper.save(new PersonPO());      System.out.println("进行第二次查询...");     EmployeePO emp2 = empMapper.findById(1L);      Assert.assertNotEquals(emp1, emp2); } 

2.4 两次相同条件查询之间, 执行了任意设置flushCache=true的查询, 一级缓存失效

  • 使用不同的sqlSession 进行任何设置了flushCache=true的查询时, 也会将当前session缓存的map清空
  • 观察日志, 第二次查询发送了查询sql, 且emp1 和 emp2 对象引用不同
    // 测试一级缓存失效: 两次相同条件查询之间, 执行了任意设置flushCache=true的查询 @Test public void test_invalid3(){      SqlSession sqlSession = SqlSessionUtil.openSession(false);      EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class);     PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);       System.out.println("进行第一次查询...");     EmployeePO emp1 = empMapper.findById(1L);      // personMapper 的findById 设置了flushCache=true, 所以执行完之后, 会清空缓存.     personMapper.findById(1);       System.out.println("进行第二次查询...");     EmployeePO emp2 = empMapper.findById(1L); } 

2.5 两次相同条件查询之间, 显示执行了清除缓存方法, 一级缓存失效

  • 显示调用sqlSession的clearCache 方法, 清空当前session缓存的map
  • 观察日志, 第二次查询发送了查询sql, 且emp1 和 emp2 对象引用不同
// 测试一级缓存失效: 两次相同条件查询之间, 显示执行了清除缓存方法 @Test public void test_invalid4(){      SqlSession sqlSession = SqlSessionUtil.openSession(false);      EmployeeMapper empMapper1 = sqlSession.getMapper(EmployeeMapper.class);     EmployeeMapper empMapper2 = sqlSession.getMapper(EmployeeMapper.class);      System.out.println("进行第一次查询...");     EmployeePO emp1 = empMapper1.findById(1L);      // 清除当前session 的缓存     sqlSession.clearCache();      System.out.println("进行第二次查询...");     EmployeePO emp2 = empMapper2.findById(1L);      Assert.assertNotEquals(emp1, emp2); } 

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

抢沙发

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

专注Java技术 100年

联系我们联系我们

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

支付宝扫一扫打赏

微信扫一扫打赏