别再跟我说你不理解 @Transactional 为什么会失效了!省流版解读

news2024/11/27 20:25:33

别再跟我说你不理解 @Transactional 原理了!省流版解读

    • 前言
    • user 表初始数据
    • 隔离级别:NESTED 案例一
    • 隔离级别:NESTED 案例一省流版答案解读
    • 隔离级别:NESTED 案例一省流版答案源码入口
    • 隔离级别 Propagation.NESTED 省流版源码剖析
    • 隔离级别:NESTED 案例二
    • 隔离级别:NESTED 案例二省流版答案解读
    • 其他隔离级别:REQUIRED、REQUIRES_NEW
    • 码字还是比较耗时的,后续发布对应的源码级别讲解视频到公众号上
    • 本文对应代码地址(包含SQL)

精读版:全面解读spring注解事务失效场景,伪代码+图文深度解析spring源码运行过程

前言

老早前精读过 @Transactional 的源码,现在有时间提炼提炼一下里面的精华出一期,从源码角度剖析 @Transactional 是怎么开启事务的?@Transactional 回滚流程又是怎样的?的角度出发,帮助大家工作中合理的使用 @Transactional 这个注解。

user 表初始数据

在这里插入图片描述

隔离级别:NESTED 案例一

  1. nestedMethodA 将 id 为 1 的数据的 username 修改 nestedMethodA
  2. nestedMethodB 将 id 为 2 的数据的 username 修改 nestedMethodB
  3. nestedMethodC 将 id 为 3 的数据的 username 修改 nestedMethodC
  4. 最后主事务 将 id 为 4 的数据的 username 修改 mainplus

思考:最后谁能更新成功?????

/**
 * A,B成功,C失败抛出异常进入 catch 逻辑
 */
@Transactional(propagation = Propagation.NESTED)
@Override
public void main() {
    try {
        tabUserService.nestedMethodA();
        tabUserService.nestedMethodB();
        tabUserService.nestedErrorMethodC();
        tabUserService.update(new LambdaUpdateWrapper<TabUser>()
                .eq(TabUser::getId, "4")
                .set(TabUser::getUsername, "mainplus"));
    } catch (Exception e) {
        System.err.println(e.getMessage());
    }
}

隔离级别:NESTED 案例一省流版答案解读

只有 nestedMethodA、nestedMethodB 方法能更新成功

在这里插入图片描述
原因 NESTED 是基于回滚点回滚事务的,生成的回滚点的位置,如下,当 nestedErrorMethodC 方法抛出异常后,异常进入到 catch 代码块中,导致

tabUserService.update(new LambdaUpdateWrapper<TabUser>()
        .eq(TabUser::getId, "4")
        .set(TabUser::getUsername, "mainplus"))

这段代码没有执行,因此 id 为 4 的数据没有更新。由于 catch 代码块中并没有接着向上抛出此异常,因此没有触发回滚主事务的操作,同时因为 nestedErrorMethodC 抛出异常,触发了回滚到回滚点 C 的逻辑,因此回滚点 C 以下的代码全部被回滚了。而 nestedMethodA、nestedMethodB 事务不受影响,因此

只有 nestedMethodA、nestedMethodB 方法能更新成功

/**
 * A,B成功,C失败抛出异常进入 catch 逻辑
 */
@Transactional(propagation = Propagation.NESTED)
@Override
public void main() {
    //主事务
    try {
        //回滚点 A
        tabUserService.nestedMethodA();
        //回滚点 B
        tabUserService.nestedMethodB();
        //回滚点 C
        tabUserService.nestedErrorMethodC();
        tabUserService.update(new LambdaUpdateWrapper<TabUser>()
                .eq(TabUser::getId, "4")
                .set(TabUser::getUsername, "mainplus"));
    } catch (Exception e) {
        System.err.println(e.getMessage());
    }
}

隔离级别:NESTED 案例一省流版答案源码入口

@Transactional 注解封装了如下三大逻辑

  1. 生成切面,(被 @Transactional 标注的方法的所在类会被生成一个代理对象)
  2. 开启事务,(执行完目标方法前,会先执行被 Spring 封转好的开启事务的逻辑)
  3. 提交事务,(执行完目标方法后,会执行被 Spring 封转好的提交事务的逻辑)
  4. 回滚事务

就拿下面这段代码举例来说,首先会为 TabUserService 生成一个代理对象,@Transactional 注解封装了如下三大逻辑中的点一。

@Service
public class TabUserServiceImpl extends ServiceImpl<TabUserMapper, TabUser> implements TabUserService {
    @Autowired
    private TabUserService tabUserService;

    /**
     * A,B成功,C失败抛出异常进入 catch 逻辑
     */
    @Transactional(propagation = Propagation.NESTED)
    @Override
    public void main() {
        try {
            //回滚点 A
            tabUserService.nestedMethodA();
            //回滚点 B
            tabUserService.nestedMethodB();
            //回滚点 C
            tabUserService.nestedErrorMethodC();
            tabUserService.update(new LambdaUpdateWrapper<TabUser>()
                    .eq(TabUser::getId, "4")
                    .set(TabUser::getUsername, "mainplus"));
        } catch (Exception e) {
            System.err.println(e.getMessage());
        }
    }
}

@Transactional 注解封装了如下三大逻辑中的 点二源码入口 如下 DataSourceTransactionManager.doBegin(),省流版不多逼逼,大家自行去 debug,debug 下面的这段代码你将获得如下问题的全套解析:

  1. ThredLocal 在 @Transactional 源码中是如何应用的?
  2. @Transactional(propagation = Propagation.NESTED) Spring 事务中的每个隔离级别是如何生效的?
  3. @Transactional 注解设计的思想
    在这里插入图片描述
    @Transactional 注解封装了如下三大逻辑中的 点三、点四源码入口 如下 TransactionAspectSupport.invokeWithinTransaction。最新的 @Transactional 源码里面用到了一些函数式接口,用于回掉用的,不清楚这方面的小伙伴,可以先去了解下函数式接口。

在这里插入图片描述

隔离级别 Propagation.NESTED 省流版源码剖析

在这里插入图片描述
回滚点是如何被保存的?源码入口如下:

AbstractPlatformTransactionManager.handleExistingTransaction()

在这里插入图片描述
如何根据回滚点回滚,源码入口如下

AbstractTransactionStatus.rollbackToHeldSavepoint()

在这里插入图片描述

隔离级别:NESTED 案例二

nestedMethodA、nestedMethodB、nestedErrorMethodC、主事务均更新失败。

/**
 * A,B成功,C失败抛出异常进入 catch 逻辑
 */
@Transactional(propagation = Propagation.NESTED)
@Override
public void main() {
    //主事务
    try {
        //回滚点 A
        tabUserService.nestedMethodA();
        //回滚点 B
        tabUserService.nestedMethodB();
        //回滚点 C
        tabUserService.nestedErrorMethodC();
        tabUserService.update(new LambdaUpdateWrapper<TabUser>()
                .eq(TabUser::getId, "4")
                .set(TabUser::getUsername, "mainplus"));
    } catch (Exception e) {
        System.err.println(e.getMessage());
        //异常抛到主事务
        throw e;
    }
}

隔离级别:NESTED 案例二省流版答案解读

NESTED 隔离级别下的事务,会和主事务共用一个数据库连接(源码入口如下),虽然 nestedErrorMethodC 方法也是 NESTED 隔离级别,只会回滚自己,但是异常被 catch 捕获后,接着向上抛,抛到了主事务中,导致了主事务回滚了,因为 nestedMethodB、nestedMethodA 与主事务共用一个数据库连接,因此一块回滚了。导致nestedMethodA、nestedMethodB、nestedMethodC连体回滚更新失败。主事务更新失败是因为代码没有得到执行。
在这里插入图片描述

其他隔离级别:REQUIRED、REQUIRES_NEW

使用上,就字面意思,有时间接着举几个对应的例子,持续更新中~~~~
在这里插入图片描述

码字还是比较耗时的,后续发布对应的源码级别讲解视频到公众号上

大家可以先关注我一波,或者关注一下公众号,这段时间上班有点忙,后续有时间更新,敬请期待~~~~~~~~

在这里插入图片描述

本文对应代码地址(包含SQL)

代码仓库里面自行查找下载即可
https://gitcode.net/users/qq_42875345/projects

在这里插入图片描述

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

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

相关文章

Fiddler Everywhere for Mac:一款强大且实用的网络调试工具

Fiddler Everywhere是一款备受Mac用户喜爱的网络调试工具&#xff0c;它具有强大的功能和易用性。作为一款老牌抓包工具&#xff0c;Fiddler Everywhere在Mac平台上拥有广泛的应用场景&#xff0c;无论是Web开发、移动应用开发还是网络调试&#xff0c;它都能提供全面的解决方案…

[论文阅读] CLRerNet: Improving Confidence of Lane Detection with LaneIoU

Abstract 车道标记检测是自动驾驶和驾驶辅助系统的重要组成部分。采用基于行的车道表示的现代深度车道检测方法在车道检测基准测试中表现出色。通过初步的Oracle实验&#xff0c;我们首先拆分了车道表示组件&#xff0c;以确定我们方法的方向。我们的研究表明&#xff0c;现有…

单链表(增删改查)【超详细】

目录 单链表 1.单链表的存储定义 2.结点的创建 3.链表尾插入结点 4.单链表尾删结点 5.单链表头插入结点 6.单链表头删结点 7.查找元素&#xff0c;返回结点 8.在pos结点前插入一个结点 ​编辑 9.在pos结点后插入一个结点 10.删除结点 11.删除pos后面的结点 12.修改…

XOR Construction

思路&#xff1a; 通过题目可以得出结论 b1^b2a1 b2^b3a2 ....... bn-1^bnan-1 所以就可以得出 (b1^b2)^(b2^b3)a1^a2 b1^b3a1^a2 有因为当确定一个数的时候就可以通过异或得到其他所有的数&#xff0c;且题目所求的是一个n-1的全排列 那么求出a的前缀异或和arr之后…

微软surface laptop禁用触摸屏(win10、设备管理器)

参考链接&#xff1a; 在屏幕中启用和禁用触摸屏Windows 设置如下

asp.net校园招聘管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net 校园招聘管理系统是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言开发 应用技术&#xff1a;asp.net c#s…

黄执中老师人际说服课思考总结(个人笔记整理 ②)

前言&#xff1a; 沟通和说服的区别&#xff1a;为什么沟通不能解决问题&#xff0c;处于劣势的一方&#xff08;承受问题的那方&#xff09;才想去沟通&#xff08;对方没有沟通动力&#xff09;。说服是温柔而有力的学科 - 劣势一方的武器。 说服是一门影响人的学问&#xff…

谷歌浏览器安装 vue-devtools 拓展,仅需3分钟,提供插件

1、vue-devtools 扩展 存储在百度网盘地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1LDIJxG26tOHtUe_aUh_pEA 提取码&#xff1a;v81r 下载下来后是一个.crx 文件 2、浏览器打开扩展程序 1、可以通过地址访问 chrome://extensions/ 2、可以自行找到相应位置…

探索双十一:从技术角度剖析电商狂欢节

每年的11月11日&#xff0c;全球最大的在线购物狂欢节“双十一”在中国掀起了一场规模空前的消费风暴。以阿里巴巴为代表的电商平台和众多品牌商家&#xff0c;不仅为消费者提供了数以亿计的优惠商品&#xff0c;同时也将这一活动打造成了一个科技与商业完美结合的标志事件。本…

ogg怎么转mp3格式?三个方法值得一试!

Ogg格式的缺点很多&#xff0c;比如其播放兼容性差、普及性差、无优势、对多声道系统的限制、专业音频制作软件不支持&#xff0c;但是保不齐我们有时候就有一个音频是ogg格式&#xff0c;那么如何把他转换成兼容性更高的MP3格式呢?下面介绍了三种常用的方法。 方法一&#xf…

ChatGPT:如何安装使用插件?超详细的教程!

1.最简单的方法 直接使用油猴&#xff0c;里边能搜索到的插件都可以用 2.官方插件使用 ChatGPT Plus引入插件后&#xff0c;功能暴强许多&#xff0c;比如可以联网、可以生成图表、可以分析视频、可以与PDF交谈等。但有不少小伙伴还不知道怎么安装使用ChatGPT插件&#xff0c;所…

【分享贴】需求变更、项目延误,项目经理应该如何应对?

案例分享&#xff1a; 项目经理小李跟进了一年半的项目&#xff0c;眼看着要到交付验收的阶段了&#xff0c;甲方的对接人却临时更换了&#xff0c;现在面临着一系列他无法处理的问题&#xff0c;项目目前推进困难。 案例背景&#xff1a; 小李在跟原甲方对接人合作时&#x…

【MySQL】rank()、row_number()、dense_rank()用法详解

建表测试 测试表数据&#xff1a;test1 CREATE DATABASE /*!32312 IF NOT EXISTS*/db_test /*!40100 DEFAULT CHARACTER SET utf8 */; USE db_test; /*Table structure for table test1 */ DROP TABLE IF EXISTS test1; CREATE TABLE test1 ( id int(10) NOT NULL, score i…

十个使用Spring Cloud和Java创建微服务的实践案例

在使用Java构建微服务时&#xff0c;许多人认为只要学习一些微服务设计模式就足够了&#xff0c;比如CQRS、SAGA或每个微服务一个数据库。虽然这是正确的&#xff0c;但同时学习一些通用的最佳实践也是很有意义的。本文分享一些最佳实践。 1 设计模块化的微服务 微服务应该专…

【Git】git的安装与使用教程

【Git】git的安装与使用教程 1.简介1.1.什么是Git1.2.Git与SVN的区别 二、安装Git三、注册Gitee帐号四、使用Git进行上传与下载代码五、使用Git代码冲突六、Git常用命令 1.简介 1.1.什么是Git Git是一个分布式版本控制系统&#xff0c;用于跟踪和管理项目代码的变更。它可以记…

【KingbaseES】R6 Liunx下使用命令行部署数据库集群

【KingbaseES】R6命令行部署数据库集群 A.数据库安装包下载软件下载页面授权下载页面 B.数据库集群部署软件安装第一步&#xff1a;创建Kingbase用户第二步&#xff1a;上传安装包1.创建Kingbase用户和准备安装目录2.使用FTP工具上传安装包镜像和授权文件到install目录下并授权…

【Truffle】四、通过Ganache部署连接

目录 一、下载安装 Ganache&#xff1a; 二、在本地部署truffle 三、配置ganache连接truffle 四、交易发送 除了用Truffle Develop&#xff0c;还可以选择使用 Ganache, 这是一个桌面应用&#xff0c;他同样会创建一个个人模拟的区块链。 对于刚接触以太坊的同学来说&#x…

【ATTCK】MITRE Caldera 朴素贝叶斯规划器

CALDERA是一个由python语言编写的红蓝对抗工具&#xff08;攻击模拟工具&#xff09;。它是MITRE公司发起的一个研究项目&#xff0c;该工具的攻击流程是建立在ATT&CK攻击行为模型和知识库之上的&#xff0c;能够较真实地APT攻击行为模式。 通过CALDERA工具&#xff0c;安全…

个人怎么投资伦敦金?

伦敦金是一种被广泛交易的黄金合约&#xff0c;是投资者参与黄金市场的一种交易方式。伦敦金投资也是黄金交易中最为方便快捷的一个种类&#xff0c;在黄金交易市场中占有较大的比例&#xff0c;每天都有来自全球各地的投资者参与买卖&#xff0c;是实现财富增益的一个有效途径…

使用电阻检测仪是否能满足生产车间防静电要求

在现代工业生产中&#xff0c;静电对产品质量和人员安全造成的影响越来越受到重视。特别是在电子、半导体、化工等领域&#xff0c;静电问题可能导致产品损坏、人员触电等严重后果。因此&#xff0c;生产车间的防静电工作显得尤为重要。而电阻检测仪作为一种常用的防静电工具&a…