mybatis缓存学习笔记

83 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情

Mybatis中有一级缓存二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级缓存是指 SqlSession 级别的缓存,当在同一个 SqlSession 中进行相同的 SQL 语句查询时,第二次以 后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存1024条SQL。二级缓存是指可以跨SqlSession的缓存,是mapper级别的缓存,对于mapper级别的缓存不同的sqlsession 是可以共享的。

一级缓存

mybatis的一级缓存默认是开启的,它在一个sqlSession会话里面的所有查询操作都会保存到缓存中,一般来说一个请求中的所有增删改查操作都是在同一个sqlSession里面的,所以我们可以认为每个请求都有自己的一级缓存,如果同一个sqlSession会话中2个查询中间有一个 insert 、update或delete 语句,那么之前查询的所有缓存都会清空。

使用MyBatis开启一次和数据库的会话,MyBatis会创建出一个SqlSession对象表示一次数据库会话,在对数据库的一次会话中, 有可能会反复地执行完全相同的查询语句,每一次查询都会去查一次数据库,为了减少资源浪费,mybaits提供了一种缓存的方式(一级缓存)。

一级缓存原理:

第一次发出一个查询 sql,sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一 个 map。

  • key:MapperID+offset+limit+Sql+所有的入参
  • value:用户信息

同一个 sqlsession 再次发出相同的 sql,就从缓存中取出数据。如果两次中间出现 commit 操作(修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存。

一级缓存失效:
如果同一个sqlSession会话中2 个查询中间有一个 insert 、update或delete 语句,那么之前查询的所有缓存都会清空。因为每次增删改操作都有可能会改变原来的数据,所以必须刷新缓存。

二级缓存

二级缓存是全局的,也就是说;多个请求可以共用一个缓存,二级缓存需要手动开启。二级缓存针对的是同一个namespace,所以建议是在单表操作的Mapper中使用,或者是在相关表的Mapper文件中共享同一个缓存。一级缓存无过期时间,只有生命周期,缓存会先放在一级缓存中,当sqlSession会话提交或者关闭时才会将一级缓存刷新到二级缓存中;开启二级缓存后,用户查询时,会先去二级缓存中找,找不到在去一级缓存中找,然后才去数据库查询。

二级缓存原理(mapper)

二级缓存的范围是 mapper 级别(mapper 同一个命名空间),mapper 以命名空间为单位创建缓存数据结构,结构是 map。mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。所有的查询操作,在 CacheExecutor 中都会先匹配缓存中是否存在,不存在则查询数据库。

key:MapperID+offset+limit+Sql+所有的入参

具体使用需要配置:

  1. Mybatis 全局配置中启用二级缓存配置
    mybatis.configuration.cache-enabled=true    
  1. 在对应的 Mapper.xml 中配置 cache 节点
    <cache eviction="LRU" flushInterval="60000" size="1000"/>
  1. 在对应的 select 查询节点中添加 useCache=true

二级缓存失效: 所有的update操作(insert,delete,uptede)都会触发缓存的刷新,从而导致二级缓存失效,所以二级缓存适合在读多写少的场景中开启。

二级缓存过期时间: 需要注意的是,并不是key-value的过期时间,而是这个cache的过期时间,是flushInterval,意味着整个清空缓存cache,所以不需要后台线程去定时检测。 每当存取数据的时候,都有检测一下cache的生命时间,默认是1小时,如果这个cache存活了一个小时,那么将整个清空一下。

mybatis缓存、spring缓存和redis缓存的使用比较

  1. mybatis缓存——dao层的缓存,主要是对select查库操作的结果进行缓存。
  2. spring缓存——方法级别的缓存,主要通过在方法上添加缓存注解@CachePut、@CacheEvict来实现。
  3. redisTemplate缓存——代码级别的缓存,主要是在方法体内部通过redisTemplate模板类编码控制缓存读写。

mybatis缓存只能对sql查询结果进行缓存spring 缓存只能对方法执行结果进行缓存,不能对方法执行过程中的中间对象进行缓存。这两者的优点都是使用简单,只需简单的配置或添加注解即可实现缓存,基本不需要编码。 缺点是缓存的控制范围都是方法级别,不能缓存方法执行过程中的中间对象,有一定的使用局限性。

而通过redisTemplate进行编码控制缓存,优点是控制灵活,缺点是需要编码实现。