Mybaits二级缓存机制

265 阅读4分钟

Mybatis 二级缓存

缓存原理介绍

  • Mybatis默认开启一级缓存,也就是SqlSession级别的缓存,一级缓存是会话级别的缓存。

  • Spring boot 在集成Mybatis的时候默认每次执行sql都会去创建一个新的SqlSession,一级缓存才不会生效。

  • 二级缓存需要手动开启,因为它是一个namespace级别的缓存。

  • <settings>
      <!--开启mybatis二级缓存-->
      <setting name="cacheEnabled" value="true"></setting>
    

一级缓存

local cache(本地缓存),作用域为SqlSession,当sql发生insert/update/delete的情况,缓存就会被清空。

public int update(MappedStatement ms, Object parameter) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (this.closed) {
        throw new ExecutorException("Executor was closed.");
    } else {
        this.clearLocalCache();
        return this.doUpdate(ms, parameter);
    }
}

this.clearLocalCache 会清空缓存;

  • 一级缓存失效的四种情况
    1. 不同的SqlSession对应不同的一级缓存
    2. 同一个SqlSession但是查询条件不同
    3. 同一个SqlSession两次查询期间执行了任何一次增删改操作
    4. 同一个SqlSession两次查询期间手动清空了缓存(sqlSession.clearCache();)

二级缓存

第一步: 因为我使用的是yaml 配置,可以在yaml加入如下配置

mybatis:
  configuration:
    cache-enabled: true

如是mybaits-config.xml文件可以使用如下配置

    <settings>
        <!--开启mybatis二级缓存-->
        <setting name="cacheEnabled" value="true"></setting>
    </settings>

第二步:

<!-- xml中开启二级缓存 -->
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

这里介绍下缓存相关的属性: eviction=“FIFO”:缓存回收策略

  • LRU – 最近最少使用的:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
  • 默认的是 LRU。 flushInterval:刷新间隔,单位毫秒 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新,这里设置60秒刷新。 size:引用数目,正整数 代表缓存最多可以存储多少个对象,太大容易导致内存溢出,这里设置最多可以存储结果对象或列表512个。 readOnly:只读,true/false
  • true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。速度快,性能有优势,但是不安全。
  • false:读写缓存;会返回缓存对象的拷贝(通过序列化)。速度慢,但是安全,因此默认是 false

也可以在mapper上面添加注解开启二级缓存,注意⚠️这两种方法只能用一种,否则控制台会报错。

@CacheNamespace
public interface SysRoleMapper

第三步:

//使用mybatis二级缓存的实体类必须实现Serializable接口
public class SysRole extends BaseEntity implements Serializable
<select id="selectRolePermissionByUserId" parameterType="Long" resultMap="SysRoleResult" useCache="true" >
    <include refid="selectRoleVo"/>
    WHERE r.del_flag = '0' and ur.user_id = #{userId}
</select>

二级缓存同时也存在于实时性,对于我们某些查询需要实时性可以选择useCache=“false”来关闭二级缓存。

<update id="updateRole"  flushCache="true" parameterType="Long">
    update sys_role set role_name =#{name} where user_id = #{userId};
</update>

清空缓存,一般需要执行完commit操作都需要刷新缓存,flushCache="true”来控制缓存是否去刷新,来避免数据库的脏读。如果不需要刷新缓存则设置为false即可。

测试结果

@GetMapping("/info/getTest")
public void  test(){

    System.out.println("第一次查询数据------------------------------");
    Long userId =Long.valueOf("1");
    List<SysRole> roles =sysRoleMapper.selectRolePermissionByUserId(userId);
    System.out.println(roles);
    System.out.println("二级缓存开启------------------------------");
    List<SysRole> roles2 =sysRoleMapper.selectRolePermissionByUserId(userId);
    System.out.println(roles2);
}
第一次查询数据------------------------------
2022-07-07 15:51:02.799 [http-nio-9201-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
2022-07-07 15:51:02.799 [http-nio-9201-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@13e9b362] was not registered for synchronization because synchronization is not active
2022-07-07 15:51:02.799 [http-nio-9201-exec-3] DEBUG com.erp.system.mapper.SysRoleMapper - Cache Hit Ratio [com.erp.system.mapper.SysRoleMapper]: 0.3333333333333333
2022-07-07 15:51:02.799 [http-nio-9201-exec-3] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
2022-07-07 15:51:02.800 [http-nio-9201-exec-3] DEBUG o.m.spring.transaction.SpringManagedTransaction - JDBC Connection [HikariProxyConnection@489574255 wrapping com.mysql.cj.jdbc.ConnectionImpl@422663f] will not be managed by Spring
2022-07-07 15:51:02.801 [http-nio-9201-exec-3] DEBUG c.e.s.m.SysRoleMapper.selectRolePermissionByUserId - ==>  Preparing: select distinct r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status, r.del_flag, r.create_time, r.remark from sys_role r left join sys_user_role ur on ur.role_id = r.role_id left join sys_user u on u.user_id = ur.user_id left join sys_dept d on u.dept_id = d.dept_id WHERE r.del_flag = '0' and ur.user_id = ? 
2022-07-07 15:51:02.801 [http-nio-9201-exec-3] DEBUG c.e.s.m.SysRoleMapper.selectRolePermissionByUserId - ==> Parameters: 1(Long)
2022-07-07 15:51:02.803 [http-nio-9201-exec-3] DEBUG c.e.s.m.SysRoleMapper.selectRolePermissionByUserId - <==      Total: 1
2022-07-07 15:51:02.804 [http-nio-9201-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@13e9b362]
[com.erp.system.api.domain.SysRole@5c134554[
  roleId=1
  roleName=管理员
  roleKey=admin
  roleSort=1
  dataScope=1
  status=0
  delFlag=0
  createBy=<null>
  createTime=Fri Mar 16 11:33:00 CST 2018
  updateBy=<null>
  updateTime=<null>
  remark=管理员
]]
二级缓存开启------------------------------
2022-07-07 15:51:02.804 [http-nio-9201-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Creating a new SqlSession
2022-07-07 15:51:02.804 [http-nio-9201-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23f8f17] was not registered for synchronization because synchronization is not active
2022-07-07 15:51:02.804 [http-nio-9201-exec-3] DEBUG com.erp.system.mapper.SysRoleMapper - Cache Hit Ratio [com.erp.system.mapper.SysRoleMapper]: 0.5
2022-07-07 15:51:02.804 [http-nio-9201-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23f8f17]
[com.erp.system.api.domain.SysRole@5c134554[
  roleId=1
  roleName=管理员
  roleKey=admin
  roleSort=1
  dataScope=1
  status=0
  delFlag=0
  createBy=<null>
  createTime=Fri Mar 16 11:33:00 CST 2018
  updateBy=<null>
  updateTime=<null>
  remark=管理员
]]