Spring整合MyBatis导致一级缓存失效问题

2023-05-16

熟悉MyBatis的小伙伴都知道MyBatis默认开启一级缓存,当我们执行一条查询语句后,MyBatis会以我们查询的信息生成一个缓存key,查询的结果为value,存到一个map中,即存入一级缓存。

环境:Mybatis + Spring,MyBatis的一级缓存使用默认值,即开启一级缓存

测试1

在一个serviceImpl中连续调用三次dao层查询数据库

@GetMapping("/test")
public void test() throws JsonProcessingException {
    List<User> user = userService.getUser();
    List<User> user1 = userService.getUser();
    List<User> user2 = userService.getUser();
}

现象

日志显示,创建了三个sqlSession,查询了三次数据库

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e8fe6ec] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@8357a79] will not be managed by Spring
==>  Preparing: SELECT id,username,password FROM user
==> Parameters: 
<==    Columns: id, username, password
<==        Row: 1, 李显赫, 1343
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7e8fe6ec]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@64cc7639] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@8357a79] will not be managed by Spring
==>  Preparing: SELECT id,username,password FROM user
==> Parameters: 
<==    Columns: id, username, password
<==        Row: 1, 李显赫, 1343
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@64cc7639]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@47ede809] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@8357a79] will not be managed by Spring
==>  Preparing: SELECT id,username,password FROM user
==> Parameters: 
<==    Columns: id, username, password
<==        Row: 1, 李显赫, 1343
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@47ede809]

结论

MyBatis的一级缓存没起作用

测试2

我们在serviceImpl的方法上加入 @Transactional

@GetMapping("/test2")
@Transactional
public void test() throws JsonProcessingException {
    List<User> user = userService.getUser();
    List<User> user1 = userService.getUser();
    List<User> user2 = userService.getUser();
}

现象2

日志显示,创建了一个sqlSession,查询了一次数据库

Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4d29be04]
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7e9f4a27] will be managed by Spring
==>  Preparing: SELECT id,username,password FROM user
==> Parameters: 
<==    Columns: id, username, password
<==        Row: 1, 李显赫, 1343
<==      Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4d29be04]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4d29be04] from current transaction
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4d29be04]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4d29be04] from current transaction
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4d29be04]

结论2

MyBatis的一级缓存又起作用了

原理分析(重点)

结论:Spring将MyBatis的DefaultSqlSession类替换成了SqlSessionTemplate

MyBatis的一级缓存是基于SqlSession来实现的,对应MyBatis中sqlSession接口的默实认现类是DefaultSqlSession,如果执行的SQL相同时,并且使用的是同一个SqlSession对象,那么就会触发对应的缓存机制。

但是在Spring整合MyBatis后,Spring使用MyBatis不再是直接调用MyBatis中的信息,而是通过调用调用mybatis-spring.jar中的类,继而达到间接调用MyBatis的效果。但在mybatis-spring.jar中,引入了一个SqlSessionTemplate类,它和Spring的事务管理器共同配合,创建对应的SqlSession连接。

即在没有添加@Transactional注解的情况下,每调用一次查询SQL,就会通过SqlSessionTemplate去创建sqlSession,即相当于新创建一次连接,故而每次查询在调试结果看来就是一级缓存失效

为什么加了@Transactional注解就可以使用缓存?

核心就是注册的方法,我测试的场景是没有加@Transactional注解的时候,此处判断为false就不会再向缓存中添加数据。

当然如果判断成功就是会调用TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory))方法,将该sqlSession对象添加到对应的缓存中,数量+1

即最终注册到synchronizations对象的缓存中

缓存池使用的是一个ThreadLocal(用于处理多个线程中数据的隔离问题,内部维护一个ThreadLocalMap)来存储

synchronizations = new NamedThreadLocal<>(“Transaction synchronizations”);

总结

  • 如果我们没有添加@Transactional注解,Spring认为我的每一次查询都都是相互独立的,便开启了三次不同的事务也即是创建了三个不同的sqlSession对象。即无法使用到MyBatis的一级缓存。
  • 如果我们添加了@Transactional注解,Spring在执行了第一次查询后,会将当前线程的事务情况存储到synchronizations 的集合中,当第二次再执行查询的时候,能够在缓存中直接获取到当前的事务情况(包含sqlSession对象),即不会再去调用openSession方法,继而创建一个新的sqlSession对象,而是使用缓存中的sqlSession对象。这就保证了在添加@Transactional注解的情况下,能够走MyBatis的一级缓存
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring整合MyBatis导致一级缓存失效问题 的相关文章

  • 内网权限维持

    权限维持 以下测试均在win7 拓展方面 windows开启rdp 1 设置远程桌面端口 xff08 可以不用输 xff0c 直接第二步 xff0c 默认开启3389 xff09 reg add 34 HKLM System Current
  • 常见优秀代码汇总

    汇总常见的编程习惯 1 语义简单明确 含义 xff1a 写代码时考虑读者 xff0c 优先采取易于读者理解的写法 define THROTL UNSET 2 define THROTL NO LIMIT 1 bool throttle is
  • 2021/7/20

    8 xff1a 30 9 xff1a 00 学习打卡 9 xff1a 30 13 xff1a 00 二招刷题 15 xff1a 00 19 xff1a 00 二招刷题 1 xff0c a题 给你一个长度为N的序列 xff0c 现在需要把他们
  • python可安装软件的制作

    一 生成可执行文件 xff08 exe 安装打包工具pyinstaller 第一种 xff1a 通过win 43 R打开cmd直接使用下面的命令安装即可 pip install pyinstaller 第二种 xff1a 下载pyinsta
  • 汇编常见指令

    文章目录 常见的运算类汇编指令add指令sub指令mul乘法指令div除法指令inc xff08 自增 xff09 xff08 即C语言 43 43 xff09 dec xff08 自减 xff09 xff08 即 xff09 push x
  • 使用阿里云服务器三分钟搭建网站

    目录 一 购买服务器 二 配置云服务器 三 下载XShell编辑器 四 使用XShell与服务器建立连接 五 安装宝塔 六 配置宝塔 七 配置多个站点 一 购买服务器 注意一定要购买CentOS内核的服务器 二 配置云服务器 购买云服务器之
  • STM32 ---寄存器点灯

    1 创建工程 处理器执行程序的时候怎么执行 处理器执行程序都是先执行汇编程序 xff0c 然后在汇编程序里面跳到主函数里面 xff0c 所以要先写好汇编程序 不过这个一般官方提供了 xff0c 只需把这个文件拷到我们的工程文件夹里面 接着将
  • QMessageBox 方法大全,各种弹窗的方法

    QMessageBox Ok xff1a 显示一个OK按钮 xff1b QMessageBox Open xff1a 显示一个打开文件的按钮 xff1b QMessageBox Save xff1a 显示一个保存文件的按钮 xff1b QM
  • 【Python实现视频转文字操作】

    一 安装moviepy模块 1 如果你用的PyCharm 导包的时候报错后 可以直接按Alt 43 Shift 43 Enter install moviepy 2 也可以在终端输入 pip install moviepy 前提是安装好了p
  • 谈论flutter和jetpack compose学习优先级的背后,Android开发有着怎样的一套进阶逻辑?

    前言 xff1a 在1982年的原版电影 银翼杀手 中 xff0c 人类已经发展出了一种人造的生命形式 xff0c 很难将它们与人类区分开来 这些 复制品 被用于危险的工作 xff0c 当它们开始反抗人类主人时 xff0c 一种被称为 刀锋
  • Android中的广播机制

    说明 xff1a 本文是郭霖 第一行代码 第3版 的读书笔记 6 1 广播机制简介 Android中的广播分为两种类型 xff1a 标准广播和有序广播 标准广播 xff1a 完全异步执行的广播 xff0c 在广播发出后 xff0c 所有的B
  • 各种常用默认的端口号

    端口号的范围是从1 xff5e 65535 其中1 xff5e 1024是被RFC 3232规定好了的 xff0c 被称作 众所周知的端口 Well Known Ports xff1b 从1025 xff5e 65535的端口被称为动态端口
  • 序号的结构层次顺序

    数字序号的级别顺序为 xff1a 第一层为汉字数字加顿号 xff0c 例如 xff1a 一 二 三 xff1b 第二层为括号中包含汉字数字 xff0c 例如 xff1a xff08 一 xff09 xff08 二 xff09 xff08 三
  • Abaqus双层混凝土梁三点抗弯(Explicit显式动力学)

    建模过程 1 part 部分 建立两层混凝土棱柱体和三个圆柱体 xff0c 并赋予材料属性 2 装配part xff0c 并在三个圆柱体圆心设立参考点 3 创建分析步 step中创建Dynamic Explicit Time period
  • Linux—生成随机密码

    Linux 小技巧 当我们需要设置十几位长度的密码时 xff0c 可能需要想半天 其实我们可以利用工具来直接生成随机的密码字符串 xff0c 这样又安全又方便 1 urandom 命令 span class token punctuatio
  • MySQL基础学习

    文章目录 MySQL基础学习1 数据库基本操作2 数据的查询2 2 1数据插入2 2 2 单表查询2 2 3 order by语句2 2 4 聚集函数 xff08 aggregate functions xff09 2 2 5 连接查询2
  • C++ 快速读入输出模板(竞赛专用)

    快输快读 xff0c 在算法竞赛中 xff0c 一定程度上可以减小程序的运行时间 xff1a 快读模板1 xff1a inline int read char c 61 getchar int x 61 0 f 61 1 for isdig
  • C#窗体应用实战项目——绩效考核管理系统

    笔者入门C xff0c 熟悉C 语法之后 xff0c 来做一个Winform项目巩固知识 xff0c 记录一下学习过程 一 什么是Winform WinForm 是 Windows Form 的简称 xff0c 是基于 NET Framew
  • Win10家庭版将中文用户名修改为英文用户名

    Win10家庭版将中文用户名修改为英文用户名 前言步骤 前言 由于同学重装系统把用户名设置成中文 win10系统在登陆时自动创建中文文件夹 xff0c 中文路径会影响一些软件的安装和使用 我总结了将中文名修改为英文名的办法 步骤 第一步 x
  • 【已解决】无法加载 DLL“xxx.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)。

    目录 异常背景及产生原因解决方法 异常 无法加载 DLL xxx dll 找不到指定的模块 异常来自 HRESULT 0x8007007E 背景及产生原因 C 中采用DLLImport静态调用同事用C 43 43 写的dll算法库时 xff

随机推荐