mybatis0051-mybatis的缓存-二级缓存

本文深入探讨MyBatis的二级缓存机制,重点讲解参照缓存的配置方法及其在多表操作中避免脏数据的关键作用。通过实例演示如何在不同Mapper间共享缓存空间,确保数据一致性。
部署运行你感兴趣的模型镜像

摘要:简述mybatis的二级缓存中的参照缓存和脏数据问题

1、上篇帖子简述了mapper接口和xml文件单独某一个开启缓存的配置(https://blog.youkuaiyun.com/wrongyao/article/details/86476486),有时候需要同时为两者开启缓存,这个时候就需要用到参照缓存,配置如下

mapper接口依赖xml的缓存空间

@CacheNamespaceRef(AreaDictMapper.class)
public interface AreaDictMapper {

<mapper namespace="com.honor.mapper.AreaDictMapper">
    <!--开启二级缓存-->
    <cache/>

上述配置是areaDictMapper接口中注解方法和xml文件中的方法使用相同的缓存,会使用com.honor.mapper.AreaDictMapper命名空间的缓存配置。 

xml接口依赖mapper的缓存空间

@CacheNamespace
public interface AreaDictMapper {

 <!--开启二级缓存-->
    <cache-ref namespace="com.honor.mapper.AreaDictMapper"/>

xml文件参照mapper配置的缓存配置。这种配置必须把xml和mapper始行路径分离(即mapper接口和xml文件不能在同一个包中具体方法参考https://www.cnblogs.com/deolin/p/8195565.html

2、脏数据现象

2.1 前言:二级缓存是依赖于某个命名空间下的,mapper.xml配置缓存就是mapper的namespace,mapper接口就是接口的全限定名称,在某个命名空间下执行dml操作会清空该命名空间下的缓存信息。

根据上述内容可知,对于单表操作而言,只要开发规范(在同一个命名空间下开发,或者同时使用mapper接口和xml时设置参照缓存,不在后台直接操作数据),是不会出现脏数据的情况的。

但是实际情况中一般都不是单表操作,通常是多表连接查询,而这个查询的statementId是会挂载到某个mapper接口下的。

举个例子A表,AMapper,B表 BMapper,A,B表做连接查询,statementId放在AMapper下

如果AMapper执行dml语句,AMapper下的二级缓存会被清空,没有问题;

如果BMapper执行dml语句,AMapper下的二级缓存不会被清空,脏数据。

解决方法:让AMpper和BMapper参照同一个缓存空间。

2.2 现象描述

三张表sys_user(用户表),sys_user_role(用户权限表)和sys_role(权限表)

模拟业务需求:获取某个用户下的所有权限

sql及执行结果:

现在新建:SysUserMapper和SysRoleMapper以及对应的xml,将上述语句挂载到SysUserMapper.xml中

<mapper namespace="com.honor.mapper.SysUserMapper">
    <select id="selectRolesByUserId" resultType="com.honor.model.SysRole">
        SELECT
            sr.sys_role_id sysRoleId,
            sr.role_name roleName
        FROM
            `sys_user` su
        JOIN `sys_user_role` sur ON su.sys_user_id = sur.sys_user_id
        JOIN `sys_role` sr ON sur.sys_role_id = sr.sys_role_id
        WHERE su.sys_user_id = #{userId};
    </select>
</mapper>

分别对SysUserMapper和SysRole开启缓存

@CacheNamespaceRef(SysUserMapper.class)
public interface SysUserMapper {

<mapper namespace="com.honor.mapper.SysUserMapper">
    <!--开启二级缓存-->
    <cache/>
@CacheNamespaceRef(SysRoleMapper.class)
public interface SysRoleMapper {

<mapper namespace="com.honor.mapper.SysRoleMapper">
    <cache/>

脏数据现象:

测试代码:在第二个sqlsession中删除一条sysrole,理想情况下是要更新缓存的,不然会查到已删除的数据,但实际没有。

System.out.println("二级缓存测试开始");
        SqlSession sqlSession = sqlSessionFactory.openSession();
        SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
        List<SysRole> sysRoles = sysUserMapper.selectRolesByUserId(33);
        for (SysRole sysRole : sysRoles) {
            System.out.println(sysRole);
        }
        sqlSession.commit();
        sqlSession.close();

        System.out.println("开启一个新的sqlsession");
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SysUserMapper sysUserMapper1 = sqlSession1.getMapper(SysUserMapper.class);
        // 删除角色数据
        SysRoleMapper sysRoleMapper = sqlSession1.getMapper(SysRoleMapper.class);
        sysRoleMapper.deleteSysRoleById(10);

        List<SysRole> sysRoles1 = sysUserMapper1.selectRolesByUserId(33);
        for (SysRole sysRole : sysRoles1) {
            System.out.println(sysRole);
        }
        sqlSession1.commit();
        sqlSession1.close();

结果:只发出一条sql,缓存没有被刷新

2.3 解决办法,让SysUserMapper和SysRoleMapper公用一个缓存空间,让SysRoleMapper参照SysUserMapper(反过来也行,保证同一个就可以)配置如下:

@CacheNamespaceRef(SysUserMapper.class)
public interface SysRoleMapper {

<mapper namespace="com.honor.mapper.SysRoleMapper">
    <cache-ref namespace="com.honor.mapper.SysUserMapper"/>

结果:

删除sys_role数据也会刷新缓存,重新发送sql,这样就不会有脏数据出现了

3、总结

mybatis的二级缓存可以减轻数据库压力,加快查询,但同时也可能会出现脏数据,解决方法是设置参照缓存,但是如果有很多表连接的话,其实也不太适合用二级缓存,因为参照缓存维护起来也很繁琐,容易出错。

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值