从嵌套事务的日志看MyBatis的sqlSession生命周期

service层业务代码

@Override
public void test(){
    QueryWrapper<StoreRebateCalculateLog> queryWrapper;
    queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("delete_flag", 0);
    //执行查询A,A事务开启
    List<StoreRebateCalculateLog> storeRebateCalculateLogs = storeRebateCalculateLogDao.selectBatchIds(Arrays.asList(90010, 90011, 90012, 90013));
    //更新,开启B事务
    ((StoreRebateCalculateLogServiceImpl) AopContext.currentProxy()).updateTest(storeRebateCalculateLogs);//取当前类的代理对象执行,保证在同一个类中的@Transactional注解能够生效
}

@Transactional(rollbackFor = Exception.class)
public void updateTest(List<StoreRebateCalculateLog> storeRebateCalculateLogs1) {
    for (StoreRebateCalculateLog log: storeRebateCalculateLogs1) {
        log.setNeedRepeatCalFlag("0");
        this.storeRebateCalculateLogDao.updateById(log);
    }
}

这里先执行一个查询,然后更新操作。查询的方法是一个事务A,后面执行更新操作的方法updateTest因为采用了声明式事务,会重新开启事务,这里记为是事务B。

查看调试模式下的MyBatis执行日志

//创建sqlSession A
Creating a new SqlSession  
//为A注册事务    
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
JDBC Connection [HikariProxyConnection@8519751 wrapping com.mysql.cj.jdbc.ConnectionImpl@2c5cdd] will be managed by Spring
==>  Preparing: SELECT calculate_log_id,month_str,day_str,total_count,min_id,max_id,status,need_repeat_cal_flag,delete_flag,creation_date,created_by,version_num,last_update_date,last_updated_by,last_update_login FROM store_rebate_calculate_log WHERE calculate_log_id IN ( ? , ? , ? , ? ) AND delete_flag=0
==> Parameters: 90010(Integer), 90011(Integer), 90012(Integer), 90013(Integer)
<==    Columns: calculate_log_id, month_str, day_str, total_count, min_id, max_id, status, need_repeat_cal_flag, delete_flag, creation_date, created_by, version_num, last_update_date, last_updated_by, last_update_login
<==        Row: 90010, 2024-03, 20240308, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 9, 2024-03-17 08:40:44, 62169, 62169
<==        Row: 90011, 2024-03, 20240309, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 9, 2024-03-17 08:41:45, 62169, 62169
<==        Row: 90012, 2024-03, 20240310, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 9, 2024-03-17 08:41:45, 62169, 62169
<==        Row: 90013, 2024-03, 20240311, 0, null, null, 2, 1, 0, 2024-03-14 22:20:10, 62169, 2, 2024-03-14 23:34:23, 62169, 62169
<==      Total: 4
//释放sqlSession A    
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
//挂起sqlSession A
Transaction synchronization suspending SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
    
//创建sqlSession B    
Creating a new SqlSession
//为B注册事务      
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
JDBC Connection [HikariProxyConnection@25084448 wrapping com.mysql.cj.jdbc.ConnectionImpl@1e088a3] will be managed by Spring
==>  Preparing: UPDATE store_rebate_calculate_log SET month_str=?, day_str=?, total_count=?, status=?, need_repeat_cal_flag=?, creation_date=?, created_by=?, version_num=?, last_update_date=?, last_updated_by=?, last_update_login=? WHERE calculate_log_id=? AND version_num=? AND delete_flag=0
==> Parameters: 2024-03(String), 20240308(String), 0(Integer), 2(String), 0(String), 2024-03-14 22:20:09.0(Timestamp), 62169(Integer), 10(Integer), 2024-03-17 09:56:44.399(Timestamp), 62169(Integer), 62169(Integer), 90010(Long), 9(Integer)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754] from current transaction
==>  Preparing: UPDATE store_rebate_calculate_log SET month_str=?, day_str=?, total_count=?, status=?, need_repeat_cal_flag=?, creation_date=?, created_by=?, version_num=?, last_update_date=?, last_updated_by=?, last_update_login=? WHERE calculate_log_id=? AND version_num=? AND delete_flag=0
==> Parameters: 2024-03(String), 20240309(String), 0(Integer), 2(String), 0(String), 2024-03-14 22:20:09.0(Timestamp), 62169(Integer), 10(Integer), 2024-03-17 09:56:44.415(Timestamp), 62169(Integer), 62169(Integer), 90011(Long), 9(Integer)
<==    Updates: 1
//这里省略了一部分更新操作的日志....
    
//释放sqlSession B   
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
//提交sqlSession B       
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
//注销sqlSession B       
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
//关闭sqlSession B    
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@10c1754]
    
//恢复sqlSession A    
Transaction synchronization resuming SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
//注销sqlSession A  
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]
//关闭sqlSession A     
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@8d867b]

可以得出下面的流程图

image-20240317104042175

另外需要注意的是,如果上面的test()方法也加上@Transactional注解,结果会是一样吗?

即如下的代码:

@Override
@Transactional(rollbackFor = Exception.class) //这里的区别
public void test(){
    QueryWrapper<StoreRebateCalculateLog> queryWrapper;
    queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("delete_flag", 0);
    //执行查询A,A事务开启
    List<StoreRebateCalculateLog> storeRebateCalculateLogs = storeRebateCalculateLogDao.selectBatchIds(Arrays.asList(90010, 90011, 90012, 90013));
    //更新
    ((StoreRebateCalculateLogServiceImpl) AopContext.currentProxy()).updateTest(storeRebateCalculateLogs);//取当前类的代理对象执行,保证在同一个类中的@Transactional注解能够生效
}

@Transactional(rollbackFor = Exception.class)
public void updateTest(List<StoreRebateCalculateLog> storeRebateCalculateLogs1) {
    for (StoreRebateCalculateLog log: storeRebateCalculateLogs1) {
        log.setNeedRepeatCalFlag("0");
        this.storeRebateCalculateLogDao.updateById(log);
    }
}

跟踪日志发现:

//这里只截取中间部分有差异的日志
==>  Preparing: SELECT calculate_log_id,month_str,day_str,total_count,min_id,max_id,status,need_repeat_cal_flag,delete_flag,creation_date,created_by,version_num,last_update_date,last_updated_by,last_update_login FROM store_rebate_calculate_log WHERE calculate_log_id IN ( ? , ? , ? , ? ) AND delete_flag=0
==> Parameters: 90010(Integer), 90011(Integer), 90012(Integer), 90013(Integer)
<==    Columns: calculate_log_id, month_str, day_str, total_count, min_id, max_id, status, need_repeat_cal_flag, delete_flag, creation_date, created_by, version_num, last_update_date, last_updated_by, last_update_login
<==        Row: 90010, 2024-03, 20240308, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 11, 2024-03-17 10:46:48, 62169, 62169
<==        Row: 90011, 2024-03, 20240309, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 11, 2024-03-17 10:47:55, 62169, 62169
<==        Row: 90012, 2024-03, 20240310, 0, null, null, 2, 1, 0, 2024-03-14 22:20:09, 62169, 11, 2024-03-17 10:48:03, 62169, 62169
<==        Row: 90013, 2024-03, 20240311, 0, null, null, 2, 1, 0, 2024-03-14 22:20:10, 62169, 4, 2024-03-17 10:48:03, 62169, 62169
<==      Total: 4
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1f057a7]

//发现这里更新时是从当前的会话中取的sqlSession,用的是同一个sqlSession,没有创建新的sqlSession
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1f057a7] from current transaction
==>  Preparing: UPDATE store_rebate_calculate_log SET month_str=?, day_str=?, total_count=?, status=?, need_repeat_cal_flag=?, creation_date=?, created_by=?, version_num=?, last_update_date=?, last_updated_by=?, last_update_login=? WHERE calculate_log_id=? AND version_num=? AND delete_flag=0
==> Parameters: 2024-03(String), 20240308(String), 0(Integer), 2(String), 0(String), 2024-03-14 22:20:09.0(Timestamp), 62169(Integer), 12(Integer), 2024-03-17 11:21:30.178(Timestamp), 62169(Integer), 62169(Integer), 90010(Long), 11(Integer)
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1f057a7]

从日志可以发现后面更新时是从当前的会话中取的sqlSession,用的是同一个sqlSession,没有创建新的sqlSession,这是什么原因呢?

因为在调用的方法test()加上@Transactional注解后,其实省略了propagation属性,而propagation的默认值就是 Propagation.REQUIRED,也就是说如果当前开启了事务,就不会创建新的事务。

其实上面的注解相当于

 @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)

所以才有了上面的结果。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

区块链推广海外市场怎么做,CloudNEO服务商免费为您定制个性化营销方案

随着区块链技术的不断发展和应用场景的扩大&#xff0c;区块链项目希望能够进入海外市场并取得成功已成为越来越多公司的目标之一。然而&#xff0c;要在海外市场推广区块链项目&#xff0c;需要采取有效的营销策略和措施。作为您的区块链项目营销服务商&#xff0c;CloudNEO将…

深度学习——SAM(Segment-Anything)代码详解

目录 引言代码目录segment-anything 代码详解build_sam.pypredictor.pyautomatic_mask_generator.py 引言 从去年年初至今&#xff0c;SAM(Segment Anything )已经问世快一年了&#xff0c;SAM凭借其强大而突出的泛化性能在各项任务上取得了优异的表现&#xff0c;广大的研究者…

详解MySql索引

目录 一 、概念 二、使用场景 三、索引使用 四、索引存在问题 五、命中索引问题 六、索引执行原理 一 、概念 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。暂时可以理解成C语言的指针,文章后面详解 二、使用场景 数据量较大&#xff0c;且…

【图像分割】使用Otsu 算法及迭代计算最佳全局阈值估计并实现图像分割(代码实现与分析)

本实验要求理解全局阈值分割的概念&#xff0c;并实现文本图像分割。需要大家深入理解Ostu 算法的实现过程及其迭代原理&#xff0c;同时通过学习使用Otsu 算法及其迭代&#xff0c;实践图像分割技术在文本图像处理中的应用。 以下将从实验原理、实验实现、实验结果分析三部分对…

老阳视频号带货项目,究竟是一个怎样的选择呢?

近年来&#xff0c;随着网络技术的飞速发展&#xff0c;直播带货已经成为电商行业的新宠。其中&#xff0c;网红老阳以其独特的风格和专业度&#xff0c;成功吸引了大量粉丝的关注&#xff0c;并带动了一波视频号带货的热潮。那么&#xff0c;现在跟随老阳的步伐&#xff0c;投…

sqllab第二十七A关通关笔记

知识点&#xff1a; 双引号闭合union select 大小写绕过 Union Select这里不能进行错误注入&#xff0c;无回显 经过测试发现这是一个双引号闭合 构造payload:id1"%09and%091"1 页面成功回显 构造payload:id0"%09uNion%09SElect%091,2,3%09"1 页面成功…

AI论文速读 | TPLLM:基于预训练语言模型的交通预测框架

论文标题&#xff1a;TPLLM: A Traffic Prediction Framework Based on Pretrained Large Language Models 作者&#xff1a;Yilong Ren&#xff08;任毅龙&#xff09;, Yue Chen, Shuai Liu, Boyue Wang&#xff08;王博岳&#xff09;,Haiyang Yu&#xff08;于海洋&#x…

Mysql 索引、锁与MVCC等相关知识点

文章目录 Mysql锁的类型锁使用MVCC快照读和当前读读视图【Read View】串行化的解决 索引类型存储方式区分逻辑区分实际使用区分索引失效情况 索引建立规范SQL编写规范exlpain字段解析ACID的原理日志引擎慢SQL整合SpringBoot博客记录 Mysql锁的类型 MySQL中有哪些锁&#xff1a…

2024-3-13,14(CSS)

1.复合选择器 有两个或者多个基础选择器&#xff0c;通过不同的方式组合而成。 目的是更加准确高效的选择目标元素&#xff08;标签&#xff09; 分类&#xff1a; 后代选择器&#xff1a;选中某个元素的所有后代元素 写法&#xff1a;父选择器 子选择器 {CSS属性}&#x…

软考高级:软件工程单元测试(驱动模块、被测模块、桩模块)概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

爱奇艺 CTR 场景下的 GPU 推理性能优化

01 背景介绍 GPU 目前大量应用在了爱奇艺深度学习平台上。GPU 拥有成百上千个处理核心&#xff0c;能够并行的执行大量指令&#xff0c;非常适合用来做深度学习相关的计算。在 CV&#xff08;计算机视觉&#xff09;&#xff0c;NLP&#xff08;自然语言处理&#xff09;的模型…

Spring炼气之路(炼气一层)

目录 一、IOC 1.1 控制反转是什么&#xff1f; 1.2 什么是IOC容器&#xff1f; 1.3 IOC容器的作用 1.4 IOC容器存放的是什么&#xff1f; 二、DI 2.1 依赖注入是什么&#xff1f; 2.2 依赖注入的作用 三、IOC案例实现 3.1下载Maven 3.2 配置Maven中的settings.xml文…

考研C语言复习进阶(2)

目录 1. 字符指针 2. 指针数组 3. 数组指针 3.1 数组指针的定义 3.2 &数组名VS数组名 4. 函数指针 5. 函数指针数组 6. 指向函数指针数组的指针 7. 回调函数 8.三步辗转法 9. 指针和数组笔试题解析 10. 指针笔试题 指针的主题&#xff0c;我们在初级阶段的《指…

​​SQLiteC/C++接口详细介绍之sqlite3类(十一)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;​​SQLiteC/C接口详细介绍之sqlite3类&#xff08;十&#xff09; 下一篇&#xff1a;​​SQLiteC/C接口详细介绍之sqlite3类&#xff08;十二&#xff09;&#xff08;未发表&#xff09; 33.sq…

JavaWeb07-会话

目录 一、会话跟踪技术 1.概述 2.实现方式 3.Cookie &#xff08;1&#xff09;基本使用 &#xff08;2&#xff09;原理 &#xff08;3&#xff09;存活时间 &#xff08;4&#xff09;存储中文 4.Session &#xff08;1&#xff09;基本使用 &#xff08;2&#x…

C#,图论与图算法,寻找图(Graph)中的桥(Bridge)算法与源代码

1 图(Graph)中的桥(Bridge) 如果删除无向连通图中的边会断开该图的连接,则该边就是桥。对于断开连接的无向图,定义类似,桥接是一种边移除,它增加了断开连接的组件的数量。 与连接点一样,网桥代表连接网络中的漏洞,对于设计可靠的网络非常有用。例如,在有线计算机网…

哪些视频编辑软件最好用?会声会影怎么样?2024会声会影激活

随着数字化时代的到来&#xff0c;视频编辑软件的需求量也逐渐增加。为了满足用户的需求&#xff0c;市面上涌现了很多的视频编辑软件&#xff0c;让用户不知道该如何选择。今天我们来聊聊哪些视频编辑软件最好用&#xff0c;以及会声会影怎么样&#xff1f; 视频编辑软件的选…

分布式事务基础理论解析

一、概述 1.1 定义 为了解决java 多个节点之间数据一致性问题。产生的核心原因是&#xff1a;资源存储的分布性。比如多个数据库&#xff0c;或者Mysql和Redis的数据一致性等。 1.2 产生场景 跨JVM进程产生分布式事务。即服务A和服务B分别有对应的数据库跨数据库实例产生分…

Qt QTableWidget 实现行选中及行悬浮高亮

表格整行的 selected、hover 高亮需求很常见&#xff0c;但使用 Qt 提供的开箱即用的方法根本无法实现这个需求&#xff08;至少在当前的时间节点是不行的&#xff09;&#xff1b;想要实现这个效果必须要费一点点力气&#xff0c;我们尽量选择较为简单的方法。 话不多说&…

yolo项目中如何训练自己的数据集

1.收集自己需要标注的图片 2.打开网站在线标注网站 2.1 点击右下角Get Start 2.2点击这里上传自己的图片 上传成功后有英文的显示 点击左边的Object Detection&#xff0c;表示用于目标检测 2.3选择新建标签还是从本地加载标签 如果是本地加载标签&#xff08;左边&#…