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 会清空缓存;
- 一级缓存失效的四种情况
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个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=管理员
]]