Spring-dataSource事务案例分析-使用事务嵌套时,一个我们容易忽略的地方

news/2024/9/22 18:21:14/

场景如下:

  • A_Bean 中的方法a()中调用B_Bean的b();
  • 方法都开启了事务,使用的默认的事务传递机制(即:属于同一事务);

如下两种场景会存在较大的差异:

  1. 在b()方法中出现了异常,在b()中进行捕获并处理且没有抛出新的异常,事务最终会进行提交;
  2. 在b()方法中出现了异常,在a()中进行捕获并处理且没有抛出新的异常,那么事务最终会如何呢?—— 先给结论:事务回滚

这个小差异平时编程的过程比较难留意到,会简单认为:当某个方法上面开启了事务,并且当前方法没有抛出任何异常,最终方法上面的事务一定会提交。其实这里是存在认知错误的

code如下:

java">@SpringBootTest
public class TransactionTest {@Autowiredprivate A a;@Testvoid testTransaction() throws Exception {a.a();}}@Service
public class A {@Autowiredprivate B b;@Transactionalpublic void a() {try {b.b();} catch (Exception e) {log.error("b执行异常,进行捕获且不抛出异常");}// for some db operation}}@Service
public class B {@Transactionalpublic void b() {// for some db operationthrow new RuntimeException("b-error");}
}}

为何错误?

  • 当 a() 方法调用 b() 方法时,如果两个方法都开启了事务且采用默认的事务传播行为(即事务嵌套),b() 方法的事务会加入到 a() 方法的事务中,成为同一个事务
  • 那么b()中出现异常,b中没有捕获而在a中捕获,实则已经触发b()的事务处理异常的逻辑。
  • 而a、b方法执行又同属一个事务,在b异常被事务管理器感知到后就会将当前事务标记为rollback,那么即使a最终没有感知到异常,最终a正常执行完毕后,a上面的事务管理逻辑也不会将事务进行提交,而是采取回滚的决定!

源码分析

当一个事务方法执行出现异常时(比如b()执行抛出异常时):

org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing

org.springframework.transaction.support.AbstractPlatformTransactionManager#rollback

org.springframework.transaction.support.AbstractPlatformTransactionManager#processRollback

org.springframework.jdbc.datasource.DataSourceTransactionManager#doSetRollbackOnly

org.springframework.jdbc.datasource.DataSourceTransactionManager.DataSourceTransactionObject#setRollbackOnly

org.springframework.transaction.support.ResourceHolderSupport#setRollbackOnly

当a()正常执行完毕,准备提交事务时:

org.springframework.transaction.interceptor.TransactionInterceptor#invoke

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning

org.springframework.transaction.support.AbstractPlatformTransactionManager#commit

org.springframework.transaction.support.SmartTransactionObject#isRollbackOnly

org.springframework.jdbc.datasource.DataSourceTransactionManager.DataSourceTransactionObject#isRollbackOnly

a执行完毕会进行判断:

最终还是会进行事务的回滚!

在 Spring 中,当事务被标记为 rollback-only 时,它会通知事务管理器,表示事务应该回滚。即使没有抛出新的异常,一旦事务被标记为 rollback-only,最终事务仍然会回滚。

因此,在你的情况下,如果 b() 方法中出现异常,在 a() 方法中进行了捕获并处理,但是事务b() 方法中被标记为 rollback-only,最终会导致 a() 方法的事务回滚。

如果有这种需要该如何处理?

如题:a事务嵌套b事务,不管b事务是否执行成功,只有a中最终没有抛出异常那么就需要将a提交,做到a事务不受内部嵌套事务的影响,该如何?

修改b事务的传播配置:


http://www.ppmy.cn/news/1428552.html

相关文章

【题解】NC40链表相加(二)(链表 + 高精度加法)

https://www.nowcoder.com/practice/c56f6c70fb3f4849bc56e33ff2a50b6b?tpId196&tqId37147&ru/exam/oj class Solution {public:// 逆序链表ListNode* reverse(ListNode* head) {// 创建一个新节点作为逆序后链表的头节点ListNode* newHead new ListNode(0);// 当前…

【高阶数据结构】并查集 -- 详解

一、并查集的原理 1、并查集的本质和概念 (1)本质 并查集的本质:森林。 (2)概念 在一些应用问题中,需要将 n 个不同的元素划分成一些不相交的集合。 开始时,每个元素自成一个单元素集合&…

C++修炼之路之list--C++中的双向循环链表

目录 前言 一:正式之前先回顾数据结构中的双向循环链表 二:list的简介 三:STL中list常用接口函数的介绍及使用 1.构造函数接口 2.list迭代器 范围for 3.数据的修改接口函数 4.list容量操作函数 5.list的迭代器失效 6.演示代码和测…

iOS RACScheduler 使用详解

RACScheduler 是 ReactiveCocoa 框架中的一个关键组件,用于在 iOS 开发中管理任务的并发执行。以下是如何详细使用 RACScheduler 的指南,以 Markdown 格式展示。 主要调度器 主线程调度器 用于在主线程上执行任务,通常用于 UI 更新操作。 …

2024年4月13日美团春招实习试题【第一题:好子矩阵】-题目+题解+在线评测【模拟】

2024年4月13日美团春招实习试题【第一题:好子矩阵】-题目题解在线评测【模拟】 题目描述:输入描述输出描述样例 解题思路一:模拟解题思路二:思路二解题思路三:直接判断 题目描述: 塔子哥定义一个矩阵是”好矩阵”&…

四.RocketMQ的几种消息发送方式应用

RocketMQ的几种消息发送方式应用 一:普通消息1)发送同步消息2)发送异步消息3)单向发送消息4)消费消息-负载均衡模式5)消费消息-广播模式 二:顺序消息1.顺序消息指的是:严格按照消息的发送顺序进…

ubuntu安装QEMU

qemu虚拟机的使用(一)——ubuntu20.4安装QEMU_ubuntu安装qemu-CSDN博客 遇到的问题: (1)本来使用git clone https://github.com/qemu/qemu.git fatal: 无法访问 https://github.com/qemu/qemu.git/:GnuTLS recv error (-110): …

OpenHarmony实战开发-页面深色模式适配。

介绍 本示例介绍在开发应用以适应深色模式时,对于深色和浅色模式的适配方案,采取了多种策略如下: 1. 固定属性适配:对于部分组件的颜色属性,如背景色或字体颜色,若保持不变,可直接设定固定色值…