MyBatis缓存
MyBatis包含一个非常强大的查询缓存特性,可以非常方便的配置和定义。缓存可以极大的提高查询效率
MyBatis系统中默认定义了两个级别的缓存,一级缓存和二级缓存;默认情况下,只有一级缓存开启,二级缓存的开启需要手动配置
- 一级缓存:线程级别的缓存,本地缓存、Sql Session级别的缓存
- 二级缓存:全局范围的缓存,除过当前线程,sqlSession能用外其他也可以使用 MyBatis实际是将缓存放在Map中
工程搭建
复制mybatis-dynamic-sql项目,并重命名为mybatis-cache,注意要修改pom.xml中artifactId为mybatis-cache,重新打开项目即可
一级缓存
- 一级缓存(local cache)即本地缓存,作用域默认为sqlSession,当session flush或者close后,该session中所有的cache将会被清空
- 本地缓存不能被关闭,但是可以调用clearCache()方法清空,或者改变缓存的作用域
一级缓存生效
同一会话期间只要查询过的数据都会保存在当前的sqlSession的一个Map中,Map的key为hashCode + 查询的SQLId + 编写的SQL语句 + SQL的参数
新增测试方法testCacheWithSameSession,先后获取同一个Teacher,在同一session下
@Test public void testCacheWithSameSession(){ TeacherMapper teacherMapper = openSession.getMapper(TeacherMapper.class); Teacher teacher = teacherMapper.getTeacherById(1); System.out.println(teacher); System.out.println("---------------------------------------------------"); Teacher teacher1 = teacherMapper.getTeacherById(1); System.out.println(teacher1); } 复制代码
执行测试
从控制台输出内容可以看出,只执行了一次查询SQL。
一级缓存失效的几种情况
- 不同的sqlSession对应不同的一级缓存
- 同一个sqlSession但是查询条件不同
- 同一个sqlSession两次查询期间执行了一次更新操作
- 同一个sqlSession两次查询期间手动清空了缓存
同一个sqlSession但是查询条件不同
不同的sqlSession使用不同的一级缓存,只有在同一个sqlSession期间查询到的数据会保存在这个sqlSession中,下次查询才可以从缓存中拿到
新增测试方法testCacheWithDiffSession
@Test public void testCacheWithDiffSession(){ SqlSession sqlSession1 = sqlSessionFactory.openSession(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); TeacherMapper teacherMapper1 = sqlSession1.getMapper(TeacherMapper.class); TeacherMapper teacherMapper2 = sqlSession2.getMapper(TeacherMapper.class); teacherMapper1.getTeacherById(1); teacherMapper2.getTeacherById(1); sqlSession1.close(); sqlSession2.close(); } 复制代码
执行测试
控制台输出两条SQL语句
同一个sqlSession但是查询条件不同
同一个方法,不同的参数,也可能之前没有执行过没有缓存数据,还是会发新的SQL
增加测试方法testCacheWithSameSessionByDiffCondition
@Test public void testCacheWithSameSessionByDiffCondition(){ SqlSession sqlSession1 = sqlSessionFactory.openSession(); TeacherMapper teacherMapper1 = sqlSession1.getMapper(TeacherMapper.class); teacherMapper1.getTeacherById(1); teacherMapper1.getTeacherById(2); sqlSession1.close(); } 复制代码
执行测试
控制台输出两条SQL语句
同一个sqlSession两次查询期间执行了一次更新操作
更新操作包括删除和新增,即使操作的不是要查询的数据也会把缓存清空
新增测试方法testCacheWithSameSessionAndConditionAfterUpdate()
@Test public void testCacheWithSameSessionAndConditionAfterUpdate(){ SqlSession sqlSession1 = sqlSessionFactory.openSession(); TeacherMapper teacherMapper1 = sqlSession1.getMapper(TeacherMapper.class); teacherMapper1.getTeacherById(1); Teacher teacher3 = new Teacher(); teacher3.setId(3); teacher3.setClassName("三年三十班"); teacherMapper1.updateTeacher(teacher3); teacherMapper1.getTeacherById(1); sqlSession1.close(); } 复制代码
执行测试
控制台输出了两条SQL语句
同一个sqlSession两次查询期间手动清空缓存
增加测试方法testCacheWithSameSessionAndConditionAfterCleanCacheManually()
@Test public void testCacheWithSameSessionAndConditionAfterCleanCacheManually(){ SqlSession sqlSession1 = sqlSessionFactory.openSession(); TeacherMapper teacherMapper1 = sqlSession1.getMapper(TeacherMapper.class); teacherMapper1.getTeacherById(1); // 手动清空当前SqlSession的一级缓存 sqlSession1.clearCache(); teacherMapper1.getTeacherById(1); sqlSession1.close(); } 复制代码
执行测试
控制它输出两条SQL语句
每次查询,MyBatis都会先看看缓存中有没有数据,如果没有才会发送新的SQL,每个SqlSession都有自己的一级缓存