Spring 事务管理及失效总结
所谓事务管理,其实就是“按照给定的事务规则来执行提交或者回滚操作”。
Spring 并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给 Hibernate 或者 JTA 等持久化机制所提供的相关平台框架的事务来实现。
Spring 事务管理器接口: org.springframework.transaction.PlatformTransactionManager ,通过这个接口,Spring 为各个平台如 JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager) 等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
Spring 事务的分类
Spring 提供了两种事务管理方式:声明式事务管理和编程式事务管理。对不同的持久层访问技术,编程式事务提供一致的事务编程风格,通过模板化的操作一致性地管理事务;而声明式事务基于 Spring AOP 实现,却并不需要程序开发者成为 AOP 专家,亦可轻易使用 Spring 的声明式事务管理。
声明式事务
Spring 的声明式事务管理是建立在 Spring AOP 机制之上的,其本质是对目标方法前后进行拦截,并在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
简单地说,声明式事务是编程式事务 + AOP 技术包装,使用注解进行扫包,指定范围进行事务管理。声明式事务管理要优于编程式事务管理,这正是 Spring 倡导的非侵入式的开发方式。
示例:
@Transactional
public void transactionDemo {// TODO 业务代码
}
编程式事务
在 Spring 出现以前,编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中显式调用 beginTransaction()、commit()、rollback() 等事务管理相关的方法,这就是编程式事务管理。
简单地说,编程式事务就是在代码中显式调用开启事务、提交事务、回滚事务的相关方法,因此代码侵入性较大。
示例:
@Autowired
private PlatformTransactionManager transactionManager;public void transactionDemo() {TransactionStatus transactionStatus = this.transactionManager.getTransaction(new DefaultTransactionDefinition());try {// TODO 业务代码// 提交事务this.transactionManager.commit(transactionStatus);} catch (Exception e) {// 回滚事务this.transactionManager.rollback(transactionStatus);}
}
Spring 事务的原理
使用 AOP 环绕通知 和 异常通知。
注意: 在使用 Spring 事务时不能使用 try-catch 进行异常捕获,要将异常抛给外层,使其进行异常拦截,触发事务机制。
事务的传播行为
所谓事务的传播行为是指如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。事务传播行为是为了解决业务层方法之间互相调用的事务问题。
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
在 Spring 中有七种事务传播行为, 下面我们就来看看吧。
REQUIRED
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。@Transactional 注解默认使用就是这个事务传播行为。
也就是说:
- 如果外部方法没有开启事务的话,REQUIRED 修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
- 如果外部方法开启事务并且被 REQUIRED 的话,所有 REQUIRED 修饰的内部方法和外部方法均属于同一事务,只要一个方法回滚,整个事务均回滚。
示例:
/*** @author star*/
public class ClassA {@Transactional(propagation = Propagation.REQUIRED)public void methoA() {// TODO 业务代码ClassB classB = new ClassB();classB.methodB();}
}/*** @author star*/
public class ClassB {@Transactional(propagation = Propagation.REQUIRED)public void methodB() {// TODO 业务代码}
}
使用 REQUIRED 传播行为修饰的 methodA() 和 methodB() 的话,两者使用的就是同一个事务,只要其中一个方法发生回滚,整个事务都回滚。
REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说,不管外部方法是否开启事务,REQUIRES_NEW 修饰的内部方法会开启一个新的事务。如果外部方法开启事务,则两个事务互不干扰,相互独立,并且外部事务会挂起,等待内部事务执行完后,才继续执行。
示列:
/*** @author star*/
public class ClassA {@Transactional(propagation = Propagation.REQUIRED)public void methoA() {// TODO 业务代码ClassB classB = new ClassB();classB.methodB();}
}/*** @author star*/
public class ClassB {@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB() {// TODO 业务代码}
}
如果使用 REQUIRED 事务传播行为修饰 methodA(),使用 REQUIRES_NEW 修饰 methodB()。那么,methodA() 发生异常回滚,methodB() 是不会跟着回滚,因为 methodB() 开启了独立的事务。但是,如果 methodB() 发生异常回滚了,并且抛出的异常被 methodA() 的事务管理机制检测到了,methodA() 也会回滚。
SUPPORTS
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。这个通常是用来处理那些并非原子性的非核心业务逻辑操作。不常用。
NOT_SUPPORTED
以非事务方式运行,如果当前存在事务,则把当前事务挂起。它可以帮助将事务极可能的缩小,因为一个事务越大,它存在的风险也就越多,所以在处理事务的过程中,要保证尽可能的缩小范围。
示列:
/*** @author star*/
public class ClassA {@Transactional(propagation = Propagation.REQUIRED)public void methoA() {// TODO 业务代码ClassB classB = new ClassB();classB.methodB();}
}/*** @author star*/
public class ClassB {@Transactional(propagation = Propagation.NOT_SUPPORTED)public void methodB() {// TODO 执行 1000 次非核心业务逻辑}
}
假如 methodB() 执行循环 1000 次的非核心业务逻辑操作,并且它处在 methodA() 的事务中,这样会造成事务太大,导致出现一些难以考虑周全的异常情况。所以,使用 NOT_SUPPORTED 修饰 methodB(),当执行到 methodB() 时,将 methodA() 的事务挂起,等 methodB() 以非事务的状态运行完成后,再继续 methodA() 的事务。
NEVER
以非事务方式运行,如果当前存在事务,则抛出抛出Runtime 异常,强制停止执行。
如果 methodA() 是使用 REQUIRED 修饰的, 而methodB() 的是使用 NEVER 修饰的。当执行到 methodB() 时,就要抛出异常了。
MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。也就是说,MANDATORY 要求上下文中必须要存在事务,否则就会抛出异常。
配置 MANDATORY 级别的事务是有效控制上下文调用代码而遗漏添加事务管理的保证手段。比如,一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用 MANDATORY 级别的事务。
NESTED
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 REQUIRED。
也就是说,如果外部方法开启事务的话,NESTED 修饰的内部方法属于外部事务的子事务,外部主事务回滚的话,子事务也会回滚,而内部子事务可以单独回滚而不影响外部主事务和其他子事务。因为 NESTED 事务它有一个 savepoint,在内部方法执行失败后进行回滚,外部方法也会回滚到 savepoint 点上。此时,如果外部方法将内部方法抛出的异常进行了捕获则会继续往下执行直到完成自己的事务。如果外部方法没有捕获异常,则会根据事务规则进行回滚。
如果外部方法未开启事务,NESTED 和 REQUIRED 作用相同,修饰的内部方法都会新开启自己的事务,且开启的事务相互独立,互不干扰。
示列:
/*** @author star*/
public class ClassA {@Transactional(propagation = Propagation.REQUIRED)public void methoA() {// TODO 业务代码ClassB classB = new ClassB();try {// savepointclassB.methodB();} catch (Exception e) {// TODO 执行其他业务}// TODO 业务代码}
}/*** @author star*/
public class ClassB {@Transactional(propagation = Propagation.NESTED)public void methodB() {// TODO 业务代码}
}
当 methodB() 执行失败后进行回滚,methodA() 也会回滚到 savepoint 点上,而 methodA() 捕获了 methodB() 抛出的异常,继续执行自己的业务代码。
基于注解 @Transactional 声明事务失效分析
在开发过程中,可能会遇到使用 @Transactional 进行事务管理时出现失效的情况。这里我们的讨论是基于事务的默认传播行为是 REQUIRED。
常见失效场景
-
如果使用 MySQL 且引擎是 MyISAM,则事务会不起作用,原因是 MyISAM 不支持事务,改成 InnoDB 引擎则支持事务。
-
注解 @Trasactional 只能加在
public修饰的方法上事务才起效。如果加在protect、private等非public修饰的方法上,事务将失效。 -
如果在开启了事务的方法内,使用了
try-catch语句块对异常进行了捕获,而没有将异常抛到外层,事务将不起效。 -
在不同类之间的方法调用中,如果 A 方法开启了事务,B 方法没有开启事务,B 方法调用了 A 方法。
- 如果 B 方法中发生异常,但不是调用的 A 方法产生的,则异常不会使 A 方法的事务回滚,此时事务无效。
- 如果 B 方法中发生异常,异常是调用的 A 方法产生的,则 A 方法的事务回滚,此时事务有效。
- 在 B 方法上加上注解 @Trasactional,这样 A 和 B 方法就在同一个事务里了,不管异常产生在哪里,事务都是有效的。
- 简单地说,不同类之间方法调用时,异常发生在无事务的方法中,但不是被调用的方法产生的,被调用的方法的事务无效。只有异常发生在开启事务的方法内,事务才有效。
-
在同一个类的方法之间调用中,如果 A 方法没开启事务,B方法开启事务,A方法调用B方法,是直接调用的,不会调用spring生成的开启事务的代理方法。但是,如果 A 方法开启 REQUIRED 事务,由于事务传播机制,B 方法会自动加入到 A 的事务中。
-
如果使用了 Spring + MVC,则
context:component-scan重复扫描问题可能会引起事务失效。
原因分析
在应用系统调用声明 @Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,在代码运行时生成一个代理对象,再由这个代理对象来统一管理。
Spring 事务是使用 AOP 环绕通知和异常通知,就是对方法进行拦截,在方法执行前开启事务,在捕获到异常时进行事务回滚,在方法执行完成后提交事务。
最后
Spring 团队建议在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。
Spring 文档中写到:Spring AOP 部分使用 JDK 动态代理或者 CGLIB 来为目标对象创建代理,如果被代理的目标对象实现了至少一个接口,则会使用 JDK 动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。
参考
https://juejin.im/post/5b00c52ef265da0b95276091#heading-9
https://blog.csdn.net/rylan11/article/details/76609643
https://blog.csdn.net/justloveyou_/article/details/73733278
相关文章:
Spring 事务管理及失效总结
所谓事务管理,其实就是“按照给定的事务规则来执行提交或者回滚操作”。 Spring 并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给 Hibernate 或者 JTA 等持久化机制所提供的相关平台框架的事务来实现。 Spring 事务…...
全局思维下的联合创新:华为携手ISV伙伴助推银行核心平稳升级
文 | 螳螂观察 作者 | 李永华 随着数字金融快速发展,对核心系统提出了“海量、高效、弹性、扩展、敏捷”等新需求,区域性银行面临核心系统升级的迫切需要,对金融科技厂商而言也催生了庞大的机遇和空间。 只是,银行核心系统是金…...
深度估计任务中的有监督和无监督训练
在计算机视觉领域,深度估计任务一直是研究的热点之一。它旨在通过图像或视频数据来推断场景中物体与相机之间的距离,为许多应用提供关键信息,如自动驾驶、机器人导航、增强现实等。在深度估计任务中,有监督训练和无监督训练是两种…...
扩散模型DDPM代码实践
安装diffusers pip install diffusers 按照diffusers官方代码 from diffusers import DDPMPipelinepipe DDPMPipeline.from_pretrained("google/ddpm-cat-256")image pipe().images[0]image.save("/data/zhz/projects/diffusion/output/ddpm_generated_imag…...
关于GPIO输入模式的配置选择
GPIO(通用输入输出)口是嵌入式系统中的重要组成部分,输入模式使得微控制器能够与外部世界进行交互。本文将探讨GPIO输入模式中的浮空输入、上拉输入和下拉输入的配置、使用场景及注意事项,并提供一些决策指导,帮助读者…...
【Kubernetes】日志平台EFK+Logstash+Kafka【实战】
一,环境准备 (1)下载镜像包(共3个): elasticsearch-7-12-1.tar.gz fluentd-containerd.tar.gz kibana-7-12-1.tar.gz (2)在node节点导入镜像: ctr -nk8s.io images i…...
今天推荐一个文档管理系统 Dorisoy.Pan
Dorisoy.Pan 是一个基于 .NET 8 和 WebAPI 构建的文档管理系统,它集成了 Autofac、MediatR、JWT、EF Core、MySQL 8.0 和 SQL Server 等技术,以实现一个简单、高性能、稳定且安全的解决方案。 这个系统支持多种客户端,包括网站、Android、iO…...
【RocketMQ】消费失败重试与死信消息
🎯 导读:本文档详细介绍了RocketMQ中的重试机制与死信消息处理方法。对于生产者而言,文档提供了如何配置重试次数的具体示例;而对于消费者,它解释了默认情况下消息消费失败后的重试策略,并展示了如何通过代…...
注册安全分析报告:闪送
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…...
SpringCloud入门
SpringCloud 原版笔记:狂神说笔记——SpringCloud快速入门23 - subeiLY - 博客园 (cnblogs.com) 一.前言 常见面试题 什么是微服务? 微服务之间是如何独立通讯的? SpringCloud 和 Dubbo有哪些区别? SpringBoot和SpringCloud&…...
js替换css主题变量并切换iconfont文件
iconfont不止有单色、双色的图标,还有很多【多色】的图标,于是不能【去色】,只能手动替换primary 新建一个iconfont,替换过主题色的,然后与旧的iconfont配合切换使用 主要如下: reqiure之前必须【清除缓…...
UI设计师面试整理-设计趋势和行业理解
在UI设计师的面试中,了解当前的设计趋势和行业动态可以让你在面试中展示你的前瞻性思维和对设计领域的深刻理解。面试官希望看到你不仅具备扎实的设计技能,还能够洞察和应用最新的设计趋势和技术。以下是一些当前的设计趋势和如何在面试中展示你对这些趋势的理解和应用的建议…...
Java零工市场小程序如何改变自由职业者生活
如今,自由职业者越来越多,他们需要找到合适的工作机会,Java零工市场小程序,为自由职业者提供了一个方便、快捷的寻找工作机会的方式,这样一来,改变了自由职业者找寻工作的方式,也提高了他们的收…...
android11 自动授权访问sdcard
目录 步骤1 步骤2 步骤1 frameworks/base/core/java/com/android/internal/os/ZygoteInit.java OsConstants.CAP_SYS_PTRACE,OsConstants.CAP_SYS_TIME,OsConstants.CAP_SYS_TTY_CONFIG,OsConstants.CAP_WAKE_ALARM,OsConstants.CAP_BLOCK_SUSPENDOsConstants.CAP_BLOCK_SUS…...
优青博导团队/免费指导/数据分析//论文润色/组学技术服务 、表观组分析、互作组分析、遗传转化实验、生物医学
🌟 教授团队领衔,全方位科研服务 🚀 一站式科研解决方案 📈 加速科研进程,让成果不再等待 📝 专业分析 定制服务 科研成功 👨🔬 立即行动,让科研成果跃然纸上 业务领…...
Mybatis 学习之 分页实现
文章目录 1. Mybatis1.1. 代码实现 2. Mybatis Plus2.1. 代码实现2.2. 特别注意 3. PageHelper3.1. 代码实现3.2. 特别注意 参考资料 1. Mybatis 1.1. 代码实现 package com.example.demo;import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot…...
Spring Boot文件上传
配置文件上传属性: 在application.properties文件中配置文件上传的属性,包括上传目录的路径、文件大小限制等。 spring.servlet.multipart.max-file-size10MB spring.servlet.multipart.max-request-size10MB处理文件上传请求 上传的文件按照日期进行…...
基于Springboot+Vue的高校体育运动会比赛系统(含源码+数据库)
1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 该系统…...
【JavaEE】——内存可见性问题
阿华代码,不是逆风,就是我疯,你们的点赞收藏是我前进最大的动力!!希望本文内容能够帮助到你! 目录 一:内存可见性问题 1:代码解释 2:结果分析 (1…...
YOLO训练参数设置解析
笔者按照教程训练完YOLO后对train训练参数配置产生兴趣,因此下文参考官方文档进行总结 Train - Ultralytics YOLO Docs YOLO 模型的训练设置包括训练过程中使用的各种超参数和配置。 这些设置会影响模型的性能、速度和准确性。 关键的训练设置包括批量大小、学习率…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
