mybatis缓存

  • 一级缓存

虽然一级缓存是自动开启的,但是和spring整合后就会出现问题。

如果已经和spring整合了,mybatis的一级缓存就会失效,因为spring会自动关闭session,所以一级缓存比较鸡肋。

  • 二级缓存

如果需要使用二级缓存,在mapper上加@CacheNamespace

springboot集成mybatis开启缓存 spring mybatis 一级缓存_spring


但是这种二级缓存同样也存在问题:

  • 如果查询和修改一个表中数据的方法不在一个mapper类中,在修改前查询并且在修改后查询时会发现查询出来的数据没有被修改,但是实际上数据库中的数据已经被修改了。
  • 但是如果查询和修改一个表中数据的方法在一个mapper类中,就不会发生上面的问题。

这是因为二级缓存的存储是有命名空间的,这个命名空间的名字就是类全名,不同的命名空间的缓存是有隔离的

所以在更新缓存的数据时只会更新同一命令名空间的数据,查询出来的数据也是存储在自己的命名空间的缓存中。

所以mybatis的二级缓存也没什么用,通常会使用第三方框架缓存

spring mybatis一级缓存失效的具体分析

mybatis和spring整合后以及缓存会失效

这是因为spring会将mybatis的mapper对象放入容器,并且真正的对象其实是一个factroybean对象,只不过返回的是mapper对象的代理对象

详情见简单模拟mybatis

而且真正执行mapper中的方法时,使用的是一个sqlsession的代理对象去执行的数据库方法,这个对象在执行完mapper中方法的逻辑后会将session关闭

在通过debug模式下进入查询语句时会发现进入的是一个代理对象,这个代理对象正是在容器中对应的一个factroybean对象返回的真正对象

springboot集成mybatis开启缓存 spring mybatis 一级缓存_一级缓存_02


底层依然是原生的mybatis的数据库查询

springboot集成mybatis开启缓存 spring mybatis 一级缓存_一级缓存_03


接着会到一个SqlSessionTemplate的包装类,执行其中的代理对象的查询方法

springboot集成mybatis开启缓存 spring mybatis 一级缓存_一级缓存_04


springboot集成mybatis开启缓存 spring mybatis 一级缓存_sql_05


在查询过后会将session关闭,这也是为什么一级缓存失效的直接原因

springboot集成mybatis开启缓存 spring mybatis 一级缓存_一级缓存_06


原生mybatis的调用链和spring mybatis的调用链的区别

mybatis–→sqlSession–→defaultSqlSession–→defaultSqlSession.selectList–→sql

spring mybatis–→sqlSession–→sqlSessionTemplate–→sqlSessionTemplate.selectList–→sqlSessionPorxy.select

这里至于为什么要关闭session,是因为sqlSession是已经被spring管理的,并没有暴露给使用者,所以我们是关不了的,这样spring就帮我们管理了,就关闭了。

而在原生的mybatis中我们是很容易拿到sqlSession,所以我们可以手动关闭session。