Mybatis的二级缓存 (默认方式)

news2024/11/22 15:57:31

目录

  • 前置
  • 生效
    • 场景一
    • 场景二
  • 失效
    • 场景一
    • 场景二
    • 场景三
    • 场景四
  • 脏数据场景


前置

什么是二级缓存:

一级缓存是基于sqlsession级别, 当一个sqlsession会话结束, 一级缓存也就结束了.
定义一级缓存为局部缓存, 那么二级缓存就是全局全局缓存
二级缓存是基于mapper文件的namespace级别,也就是说多个sqlSession可以共享一个mapper中的二级缓存区域,并且如果两个mapper的namespace 相同,即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域中。

会演示二级缓存生效/失效的场景
项目地址: https://gitee.com/xmaxm/test-code/blob/master/chaim-cache/chaim-mybatis-cache/chaim-mybatis-cache-two/README.md

前置配置:

二级缓存(全局缓存)(namespace级别)
第一步需配置: mybatis-plus.configuration.cache-enabled: true 默认true
第二步: 对应entity需要实现 Serializable
第三步: (对应的 mapper 添加 @CacheNamespace->可配缓存参数, xml 添加 标签) 或者 (mapper 添加 @CacheNamespaceRef, xml 添加 标签->可配缓存参数)
缓存可配置参数: https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#cache

注意点

@CacheNamespace(blocking = true) 属性可避免瞬时流量涌入直接打入数据库. 自定义二级缓存(后续文章会有介绍)方式是不支持该属性的, 需要考虑自己实现

源码部分

感觉要是把源码过一遍, 得从新起一篇文章才行, 后面有需要在写, 偷个懒吧, 哈哈哈哈哈!

源码入口: org.apache.ibatis.mapping.CacheBuilder#build
关键类: org.apache.ibatis.cache.Cache
默认实现: org.apache.ibatis.cache.impl.PerpetualCache
默认淘汰策略: org.apache.ibatis.cache.decorators.LruCache

相关缓存文章

Mybatis的一级缓存
Mybatis的二级缓存 (默认方式)
Mybatis的二级缓存 (Redis方式)
Mybatis的二级缓存 (ehcache方式)


生效


场景一

测试二级缓存生效: 按前置描述配置
使用mybatis plus方法

public void queryingLevelCache() {
    LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.select(SysUser::getUsername, SysUser::getPhone, SysUser::getId);
    queryWrapper.last("limit 1");
    SysUser sysUsers = sysUserMapper.selectOne(queryWrapper);
    log.info("查询成功, 观察日志, id: {}", sysUsers.getId());

    sqlSession.clearCache();

    SysUser user = sysUserMapper.selectOne(queryWrapper);
    log.info("查询成功, 观察日志, id: {}", user.getId());
}

在这里插入图片描述


场景二

测试二级缓存生效: 按前置描述配置
使用自定义SQL

public void queryingLevelCache(Integer integer) {
    SysUser sysUsers = sysUserMapper.selectHandwritingSql();
    log.info("查询成功, 观察日志, id: {}", sysUsers.getId());

    SysUser user = sysUserMapper.selectHandwritingSql();
    log.info("查询成功, 观察日志, id: {}", user.getId());
}

在这里插入图片描述


失效


场景一

测试二级缓存失效: 添加@Transactional, 使其在同一个 SqlSession, 然后手动清除缓存

@Transactional(rollbackFor = Exception.class)
public void queryingLevelCacheFail() {
    LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.select(SysUser::getUsername, SysUser::getPhone, SysUser::getId);
    queryWrapper.last("limit 1");
    SysUser sysUsers = sysUserMapper.selectOne(queryWrapper);
    log.info("查询成功, 观察日志, id: {}", sysUsers.getId());

    sqlSession.clearCache();

    SysUser user = sysUserMapper.selectOne(queryWrapper);
    log.info("查询成功, 观察日志, id: {}", user.getId());
}

在这里插入图片描述


场景二

测试二级缓存失效: 当两次查询的方式不一样, 使用mybatis的方法, 以及自定义SQL
同理, 当查询的条件以及查询的内容不一致时也会失效

public void queryingLevelCacheFail(Integer integer) {
    LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.select(SysUser::getUsername, SysUser::getPhone, SysUser::getId);
    queryWrapper.last("limit 1");
    List<SysUser> sysUsers = sysUserMapper.selectList(queryWrapper);
    log.info("查询成功, 观察日志, id: {}", sysUsers.size());

    SysUser user = sysUserMapper.selectHandwritingSql();
    log.info("查询成功, 观察日志, id: {}", user.getId());
}

在这里插入图片描述


场景三

测试二级缓存失效: 当两次查询存在之间, 存在增删改的情况

public void queryingLevelCacheFail(String string) {
    SysUser sysUsers = sysUserMapper.selectHandwritingSql();
    log.info("查询成功, 观察日志, id: {}", sysUsers.getId());

    SysUser sysUser = SysUser.builder()
            .username("潇潇")
            .email("gmail.com")
            .phone("000123")
            .password("123456")
            .sex(1)
            .state(0)
            .salt(1234)
            .build();
    sysUserMapper.insert(sysUser);
    log.info("观察新增日志, id: {}", sysUsers.getPassword());

    SysUser user = sysUserMapper.selectHandwritingSql();
    log.info("查询成功, 观察日志, id: {}", user.getId());
}

在这里插入图片描述


场景四

测试二级缓存失效:
xml 的标签指定 flushCache=“true”
注解方式SQL配置: @Options(flushCache = Options.FlushCachePolicy.TRUE)

同理还可以全局配置: 禁用mybatis一级缓存: mybatis-plus.configuration.cache-enabled: false. 默认开始 true

public void queryingLevelCacheFail(Boolean bol) {
    SysUser sysUsers = sysUserMapper.selectHandwritingSqlFail();
    log.info("查询成功, 观察日志, id: {}", sysUsers.getId());

    SysUser user = sysUserMapper.selectHandwritingSqlFail();
    log.info("查询成功, 观察日志, id: {}", user.getId());

    log.info("-----------自义定SQL的两种失效方式-----------------");

    sysUsers = sysUserMapper.selectHandwritingSqlFail2();
    log.info("查询成功, 观察日志, id: {}", sysUsers.getId());

    user = sysUserMapper.selectHandwritingSqlFail2();
    log.info("查询成功, 观察日志, id: {}", user.getId());

}
<!-- flushCache默认false. true: 每次查询走数据库查询(SQL的二级缓存失效) -->
 <select id="selectHandwritingSqlFail" resultType="com.chaim.mybatis.cache.two.entitys.SysUser" flushCache="true">
     SELECT username,phone,id FROM sys_user limit 1
 </select>
@Options(flushCache = Options.FlushCachePolicy.TRUE)
@Select("SELECT username,phone,id FROM sys_user limit 1")
SysUser selectHandwritingSqlFail2();

在这里插入图片描述
在这里插入图片描述


脏数据场景

脏数据: 前提开启二级缓存. 在两次查询之间, 做INSERT UPDATE DELETE配置其标签: flushCache=“false”, 不清空缓存,
导致第二条SQL走二级缓存获取的数据还是之前缓存的数据

    public void queryingLevelCacheError() {
        SysUser sysUser = sysUserMapper.selectHandwritingSql();
        log.info("查询成功, 观察日志, id: {}", sysUser.toString());

        sysUser.setPhone("999090912");
        sysUserMapper.updateHandwritingSql(sysUser);
        log.info("观察更新日志, id: {}", sysUser.getPassword());

        // 由于updateHandwritingSql配置不清除缓存, user的数据还是之前缓存数据(脏数据)
        SysUser user = sysUserMapper.selectHandwritingSql();
        log.info("查询成功, 观察日志, id: {}", user.toString());
    }
 <!-- flushCache默认true.
 true: 会导致本地缓存和二级缓存被清空
 false: 不会清空本地缓存和二级缓存, 即缓存的数据还是之前的(脏读) -->
 <update id="updateHandwritingSql" flushCache="false">
     UPDATE sys_user SET phone = #{phone} WHERE id = #{id};
 </update>

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/20686.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

进程和线程的区别

进程和线程的区别 文章目录进程和线程的区别进程和线程的概念一、从属关系不同二、所属基本单位不同三、资源消耗不同四、是否同步和互斥额外补充问题&#xff1a;一个进程是不是可以创建无限数量的线程&#xff1f;参考链接进程和线程的概念 在了解区别之前&#xff0c;我们先…

【Java】IO流 - 字节流

文章目录FileInputStream 介绍FileOutputStream介绍文件输入输出综合使用【拷贝】FileInputStream 介绍 创建一个txt文件&#xff0c;写入 HelloWorld 并用Java读取&#xff1a; Test public void readFile01(){//提前创建一个文件hello.txt并编辑一个HelloWorldString filePa…

Nacos 注册中心的常用配置

1.服务端地址 spring.cloud.nacos.discovery.server-addr 无 Nacos Server 启动监听的 ip 地址和端口2.服务名 spring.cloud.nacos.discovery.s ervice ${spring.application.name} 给当前的服务命名3.服务分组spring.cloud.nacos.discovery.groupDEFAULT_GROUP 设置服务所处的…

机器视觉之ros人脸识别

系列文章目录 机器视觉之ros人脸识别 ros人脸识别系列文章目录一、WIN下的环境设置二、连接摄像头设备到虚拟机三、安装摄像头驱动设备3.1判断安装usb还是uvc驱动包3.2查看摄像头设备3.3测试网络摄像头3.4安装摄像头驱动包四、调用视觉功能包五、人脸识别的调用一、WIN下的环境…

封装系统之新手操作版

一、需要软件&#xff1a;Vmware16&#xff0c;win10正版系统&#xff0c;EasySysprep5&#xff0c;EasyU_v3.6.iso 下载地址&#xff1a;EasySysprep5&#xff1a;https://www.itsk.com/thread-425990-1-1.html EasyU_v3.6&#xff1a;https://www.itsk.com/thread-426856-1-1…

【计算机视觉】不来试试图片轮廓提取?

文章目录&#x1f6a9; 前言&#x1f348; 边缘提取原理卷积用特殊的卷积核进行轮廓提取&#x1f34f; 开始轮廓提取代码&#x1f6a9; 前言 最近学到了深度学习的卷积操作&#xff0c;在卷积神经网络出现之前&#xff0c;就已经有使用卷积核 &#xff08;也叫滤波器&#xff…

NLP模型(三)——FastText介绍

文章目录1. FastText 概述2. FastText 分类模型2.1 结构2.2 n-gram3. FastText 词嵌入模型1. FastText 概述 首先&#xff0c;我们得搞清楚&#xff0c;FastText 是什么&#xff1f;有的地方说是分类模型&#xff0c;有的地方又将其用于词向量&#xff0c;那么&#xff0c;Fas…

ppt复现CVPR顶会流程图

本次目标如下图&#xff0c;难点在于立方体和矩阵格网的绘制 文末附机器学习绘图模板~ 先来绘制立方体&#xff0c;插入——形状——立方体&#xff0c;调节成如下图&#xff0c;再点击水平翻转&#xff1a; 绘制矩形&#xff0c;多绘制几个组合成矩形格网&#xff0c;右键设置…

TFT-LCD屏幕读取Flash芯片图片资源并显示

TFT-LCD屏幕读取Flash芯片图片资源并显示 在前面用TFT-LCD显示图片的实验中&#xff0c;由于图片资源过大&#xff0c;240 * 320 的图片大小为150K&#xff0c;而STM32F103ZET6的内部Flash才512K&#xff0c;最多能放三张图片&#xff0c;所以这次将图片放到外部Flash中&#…

【Java八股文总结】之Redis数据库

文章目录Redis 数据库一、Redis基础1、Redis应用场景2、Redis数据类型3、Redis常用命令4、Redis为什么速度快&#xff1f;5、Redis和Memcached的区别和共同点6、Redis和MySQL的区别&#xff1f;二、高可用1、主从复制Q&#xff1a;主从复制主要的作用?2、Redis主从复制原理Red…

Cadence之Allegro:蛇形与差分等长

文章目录 一、三种等长方法二、直接等长法设置教程1、差分设置2、analysis设置三、pin-pair法设置教程一、三种等长方法 直接等长法 适用pin和pin之间没有容抗和阻抗的情况,即pin和pin之间只有一根线、没有电阻和电容的时候才可以使用这种方法。 pin-pair法 建立Sigxplorer模形…

基于stm32的光照强度检测智能窗帘系统

资料编号&#xff1a;098 下面是相关功能视频演示&#xff1a; 98-基于stm32的光照强度检测智能窗帘系统Proteus仿真&#xff08;源码仿真全套资料&#xff09;功能介绍&#xff1a; 检测当前的光照强度&#xff0c;LCD1602显示&#xff0c;并且可以自动打开关闭窗帘&#xf…

Tomcat AJP 文件包含漏洞(CVE-2020-1938)

目录 1&#xff0e;漏洞简介 2、AJP13 协议介绍 Tomcat 主要有两大功能&#xff1a; 3&#xff0e;Tomcat 远程文件包含漏洞分析 4&#xff0e;漏洞复现 5、漏洞分析 6&#xff0e;RCE 实现的原理 1&#xff0e;漏洞简介 2020 年 2 月 20 日&#xff0c;公开CNVD 的漏洞公…

【ACL 2022】用于多标签文本分类的对比学习增强最近邻机制

论文地址&#xff1a;https://aclanthology.org/2022.acl-short.75.pdf 1. 摘要 多标签文本分类&#xff08;MLTC&#xff09;是自然语言处理中的一项基本且具有挑战性的任务。以往的研究主要集中在学习文本表示和建模标签相关性上。然而&#xff0c;在预测特定文本的标签时&…

玩转SQL语句之group by 多字段分组查询与having子句,一篇解决你的疑惑!

sql语句group by使用详解group by的基本语法基本语法什么是分组查询(一个字段)多个字段的分组查询1.两个字段的分组查询2.三个字段及N个字段进行分组查询having子句的使用基本语法having是干什么的演示分组查询select关键字后面列名书写的注意事项group by的基本语法 基本语法…

入门必写项目之图书管理系统(分析详解+完美运行+代码可拿)

文章目录一、需求分析二、思路分析三、包分类四、模块代码展示1.1书籍类&#xff08;Book&#xff09;实现1.2书架类&#xff08;BookList类&#xff09;实现2.1功能接口&#xff08;IOperation&#xff09;实现2.2增加图书&#xff08;Addoperation&#xff09;实现2.3删除图书…

家庭实验室系列文章-电脑如何配置网络唤醒 (WOL)?

前言 其实这个专题很久很久之前就想写了&#xff0c;但是一直因为各种原因拖着没动笔。 因为没有资格&#xff0c;也没有钱在一线城市买房 (&#x1f602;&#x1f602;&#x1f602;); 但是在要结婚之前&#xff0c;婚房又是刚需。 我和太太最终一起在一线城市周边的某二线城…

Pyspark学习笔记小总

pyspark官方文档: https://spark.apache.org/docs/latest/api/python/index.html pyspark案例教程: https://sparkbyexamples.com/pyspark-tutorial/ 1. 写在前面 这篇文章记录下最近学习的有关Pyspark以及用spark sql去处理大规模数据的一些常用语法&#xff0c;之前总觉得p…

中小企业办公自动化系统设计与实现(SSH)

目 录 摘 要 I ABSTRACT II 目 录 IV 第1章 绪论 1 1.1 课题背景 1 1.1.1 办公自动化概述 1 1.1.2 中小企业办公模式的现状 2 1.2 研究意义 3 1.3 设计技术及开发环境 5 1.3.1 设计技术 5 1.3.2 开发环境 7 第2章 可行性分析 9 2.1 组织和管理可行性 9 2.2 经济可行性 9 2.3 技…

动态规划模板总结(1)

动态规划思想(1) 背包问题 ​ 分类&#xff1a; 01 背包问题 ​ 含义&#xff1a;每个物体最多选1次&#xff0c;在不超过总体积的情况下价值最大图解&#xff1a; f(i,j)表示的是集合的某种属性&#xff0c;是个值。 集合是所有选法 i 只从前i个中选 朴素实现 #include&…