Spring中@Transactional注解与事务传播机制

文章目录

  • 事务传播机制
  • 事务失效的场景

事务传播机制

事务的传播特性指的是 当一个事务方法调用另一个事务方法时,事务方法应该如何执行。

事务传播行为类型外部不存在事务外部存在事务使用方式
REQUIRED(默认)开启新的事务融合到外部事务中@Transactional(propagation = Propagation.REQUIRED)适用于增删改查
PROPAGATION_SUPPORTS不开启新的事务融合到外部事务中@Transactional(propagation = Propagation.SUPPORTS)适用于查
REQUIRES_NEW开启新的事务不用外部事务,开启新的事务@Transactional(propagation = Propagation.REQUIRES_NEW)适用于内部事务和外部事务不存在业务关联的情况,如记录日志
NOT_SUPPORTED不开启新的事务不用外部事务@Transactional(propagation = Propagation.NOT_SUPPORTED)不常用
NEVER不开启新的事务抛出异常@Transactional(propagation = Propagation.NEVER)不常用
MANDATORY抛出异常融合到外部事务中@Transactional(propagation = Propagation.MANDATORY)不常用
NESTED开启新的事务融合到外部事务中,Savepoint 机制,外层回滚影响内层,内层回滚不影响外层@Transactional(propagation = Propagation.NESTED)不常用

我们平常在 Spring 中使用的注解 @Transactional,不声明 propagation 参数的情况下默认是 REQUIRED 级别。

@Transactional
public void trans() {upsert();query(); // 查log(); // 记录日志
}@Transactional(propagation = Propagation.SUPPORTS) // 外部没有事务时不用开启新的事务
public info query() {}@Transactional(propagation = Propagation.REQUIRES_NEW) // 记录日志和主事务不存在业务关联
public void log() {}

[注意] 从官方文档中可以看出,我们需要区分逻辑事务以及物理事务,在 Propagation.REQUIRES 等级下,尽管每个内部方法都可以区别于外部事务,独立定义 rollback-only 状态,但是内部逻辑事务的状态都会映射到同一个物理事务上,因此内部事务方法的 rollback-only 标志也会影响外部整个事务的 commit.

https://docs.spring.io/spring-framework/reference/data-access/transaction/declarative/tx-propagation.html

事务失效的场景

参考 https://mp.weixin.qq.com/s/m7Pfeq7n9_8s1i4Zoq8qWw

https://www.bilibili.com/video/BV14d4y1r74o/

8 大失效场景:

  1. 方法内的自调用:Spring事务是基于AOP的,只有使用代理对象调用某个方法时,Spring事务才能生效,而在一个方法中调用使用this.xxx 调用方法时,this并不是代理对象,所以会导致事务失效。

    解放办法1:把调用方法拆分到另外一个Bean中

    解决办法2:自己注入自己

    解決办法3:AopContext.currentProxy0+@EnableAspectAutoProxy(exposeProxy = true)

  2. 方法是private的:Spring事务会基于CGLIB来进行AOP,而CGLIB会基于父子类来失效(最终 Spring Bean 调用的是被增强的子类),子类是代理类,父类是被代理类,如果父类中的某个方法是private的,那么子类就没有办法重写它,也就没有办法额外增加Spring事务的逻辑。

  3. 方法是final的:原因和private是一样的,也是由于子类不能重写父类中的final的方法

  4. 单独的线程调用方法:当Mybatis或JdbcTemplate执行SQL时,会从ThreadLocal中去获取数据库连接对象,如果开启事务的线程和执行SQL的线程是同一个,那么就能拿到数据库连接对象,如果不是同一个线程,那就拿到不到数据库连接对象,这样,Mybatis或JdbcTemplate就会自己去新建一个数据库连接用来执行SQL,此数据库连接的autocommit为true,那么执行完SQL就会提交,后续再拋异常也就不能再回滚之前已经提交了的SQL了。

  5. 没加@Configuration注解:如果用SpringBoot基本没有这个问题,但是如果用的Spring,那么可能会有这个问题,这个问题的原因其实也是由于Mybatis或JdbcTemplate会从ThreadLocal中去获取数据库连接,但是ThreadLocal中存储的是一个MAP,MAP的key为Datasource对象,value为连接对象,而如果我们没有在AppConfig上添加@Configuration注解的话,会导致MAP中存的DataSource对象和Mybatis和JdbcTemplate中的DataSource对象不相等,从而也拿不到数据库连接,导致自己去创建数据库连接了。

  6. 异常被吃掉:如果Spring事务没有捕获到异常,那么也就不会回滚了,默认情况下Spring会捕获RuntimeException和Error。

    解释一下上面提到的注意点:外部事务方法 saveUserWithLog 在调用内部事务方法 logService.insertLog 时,虽然捕获了异常,但是内部事务方法有异常抛出时,整个外部事务仍然会回滚并抛出异常 Transaction rolled back because it has been marked as rollback-only,这是因为默认 @Transactional 用的是 REQUIRED 事务传播等级,内部事务方法会融合到外部事务中,内部事务方法出现异常时就会将整个 物理 connection 设置为 rollback-only,所以共用此 connection 的整个外部事务也会回滚。

    @Transactional(rollbackFor = Exception.class)
    public Integer saveUserWithLog() {try {// 默认 @Transactional(propagation = Propagation.REQUIRED) 抛出异常logService.insertLog();} catch (Exception e) {}User user = new User();user.setId(1001);user.setName("jxz_rollback");user.setAge(1);userMapper.insert(user);return user.getId();
    }
    
  7. 类没有被Spring管理

  8. 数据库不支持事务

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

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

相关文章

Python酷库之旅-第三方库Pandas(252)

目录 一、用法精讲 1191、pandas.tseries.offsets.BusinessMonthBegin.n属性 1191-1、语法 1191-2、参数 1191-3、功能 1191-4、返回值 1191-5、说明 1191-6、用法 1191-6-1、数据准备 1191-6-2、代码示例 1191-6-3、结果输出 1192、pandas.tseries.offsets.Busine…

IO流之文件

1. 文件流 2. 常用文件操作 2.1 文件创建 方式1 new File(String pathname) // 根据路径创建一个File对象 方式2 new File(File parent,String child) //根据父目录文件子路径构建 方式3 new File(String parent,String child) //根据父目录子路径构建 package com.hspedu.fil…

【从零开始的LeetCode-算法】35. 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2示例 2: 输入: …

C++(4个类型转换)

1. C语言中的类型转换 1. 隐式 类型转换: 具有相近的类型才能进行互相转换,如:int,char,double都表示数值。 2. 强制类型转换:能隐式类型转换就能强制类型转换,隐式类型之间的转换类型强相关,强制类型转换…

深度学习7 梯度下降优化、过拟合、手机价格预测

三、BP算法 3、梯度下降 w w - lr * grad: w 表示权重,lr表示学习率,grad表示梯度 传统下降方式分三类:(BGD)批量梯度下降、(MBGD)小批量梯度下降、(SGD)随…

计算机的错误计算(一百七十二)

摘要 探讨 MATLAB 对于算式 的计算误差。 例1. 在 MATLAB 中计算 的值。 直接贴图吧: 这样,MATLAB 的输出中只有3位正确数字,有效数字的错误率为 (16-3)/16 81.25% . 因为16位的正确输出为 0.2971242332737277e-18(ISReals…

手撸了一个文件传输工具

在日常的开发与运维中,文件传输工具是不可或缺的利器。无论是跨服务器传递配置文件,还是快速从一台机器下载日志文件,一个高效、可靠且简单的文件传输工具能够显著提高工作效率。今天,我想分享我自己手撸一个文件传输工具的全过程…

Linux系统编程之进程创建

概述 在Linux系统中,通过创建新的进程,我们可以实现多任务处理、并发执行和资源隔离等功能。创建进程的主要方法为:fork、vfork、clone。下面,我们将分别进行介绍。 fork fork是最常用的创建新进程的方法。当一个进程调用fork时&a…

【人工智能】用Python实现卷积神经网络(CNN)进行图像分类:从零开始的深度学习教程

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 卷积神经网络(CNN)是处理图像分类任务的核心工具,它通过卷积操作和池化机制提取图像的特征并实现分类。本文将手把手教你如何使用 Python 和深度学习框架(PyTorch)从头实现一个 CNN 模型,应用于图像…

深入探讨NIO

目录 传统阻塞IO 非阻塞IO select() epoll 总结 传统阻塞IO 非阻塞IO IO多路复用select() IO多路复用epoll 传统阻塞IO 在传统的阻塞IO模型中,当一个线程执行到IO操作(如读取数据)时,如果数据尚未准备好,它会…

新手参加2025年CTF大赛——Web题目的基本解题流程

CTF(Capture the Flag)是网络安全比赛中的一种常见形式,参赛者需要通过破解题目、发现漏洞并获取flag(标志)来获得分数。 这些问题涉及多个领域,如逆向工程、Web安全、密码学、二进制漏洞、取证分析等。CTF…

1Panel 自建邮局 - Docker Mailserver

本文首发于 Anyeの小站,点击链接 访问体验更佳 前言 首先发一段劝退说辞:我相信点进本文的人自建邮局的目的更多地是为了能用自己的域名邮箱,收发邮件? 仅收不发,推荐使用 https://www.cloudflare.com/zh-cn/develop…

QT-thread2种方式选择的优劣对比

1.第一种方式:使用 QObject 的 moveToThread() QObjectQthread class MessageWriter : public QObject {Q_OBJECT public slots:void writeDataToFile(); };threadMsgExchange new QThread();MessageWriter *writer new MessageWriter();writer->moveToThread…

【Maven】功能和核心概念

1. 什么是Maven 1.1 Maven的概念 Maven 是 Apache 软件基金会组织维护的一款自动化构建工具,专注服务于 Java 平台的项目构建和依赖管理。 1.2 为什么要使用Maven? 在项目开发中,我们需要引用各种 jar 包,引用的 jar 包可能有…

Go运行Grule引擎实现计费规则管理

Go运行Grule引擎实现计费规则管理 github位置: https://github.com/hyperjumptech/grule-rule-engine # 安装grule模块 go get -u github.com/hyperjumptech/grule-rule-engineGrule的示例代码 示例位置: https://github.com/hyperjumptech/grule-rule-engine/tree/master/e…

企业网站面临的爬虫攻击及安全防护策略

在当今数字化时代,企业网站不仅是展示企业形象的窗口,更是进行商业活动的重要平台。然而,企业网站在日常运营中面临着多种类型的爬虫攻击,这些攻击不仅会对网站的正常访问造成影响,还可能窃取敏感数据,给企…

Hive on Spark 的Pre-commit 测试

什么是 Pre-Commit 测试? Pre-Commit 测试是一种提交代码到主分支或共享代码库之前运行的一系列自动化测试,用于捕获代码中的潜在问题自动运行的测试流程。其目的是确保新提交的代码不会引入错误,破坏现有功能或降低代码质量。对于大型项目如…

android shader gl_Position是几个分量

在Android的OpenGL ES中,gl_Position是顶点着色器(Vertex Shader)的一个内置输出变量,它用于指定顶点在裁剪空间(Clip Space)中的位置。gl_Position是一个四维向量(4-component vector&#xff…

【FAQ】HarmonyOS SDK 闭源开放能力 —Push Kit(6)

1.问题描述: 推送通知到手机,怎么配置拉起应用指定的页面? 解决方案: 1、如果点击通知栏打开默认Ability的话, actionType可以设置为0, 同时可以在.clickAction.data中,指定待跳转的page页面…

vue3 + vite + antdv 项目中自定义图标

前言: 去iconfont-阿里巴巴矢量图标库 下载自己需要的icon图标,下载格式为svg;项目中在存放静态资源的文件夹下 assets 创建一个存放svg格式的图片的文件夹。 步骤: 1、安装vite-plugin-svg-icons npm i vite-plugin-svg-icons …