在 Java 开发中,事务是保证数据一致性和完整性的关键机制,尤其在涉及多步数据库操作的业务场景中不可或缺。然而,在实际开发过程中,事务常常会出现 “失效” 的情况 —— 预期的回滚没有发生,数据出现不一致。

        Java 事务(尤其是基于 Spring 的声明式事务)的正常运作依赖于一系列底层机制和约定,当这些机制被破坏或约定未被遵守时,就会导致事务失效。核心原因可归纳为以下几类:​

(1)事务传播行为配置不当:事务传播行为决定了多个事务方法相互调用时的执行规则,若配置错误(如使用PROPAGATION_SUPPORTS或PROPAGATION_NOT_SUPPORTED),会导致事务无法按预期生效。​

(2)异常处理不当:事务默认只对未捕获的RuntimeException及其子类异常回滚,若异常被手动捕获且未重新抛出,或抛出的是受检异常,会导致事务不回滚。​

(3)方法访问权限问题:Spring 事务基于 AOP 动态代理实现,若目标方法是private、final或static修饰的,代理无法生效,事务自然失效。​

(4)数据源未配置事务管理器:事务的管理依赖于事务管理器,若未为数据源正确配置PlatformTransactionManager,事务注解将无法发挥作用。​

(5)自调用问题:在同一个类中,一个非事务方法调用本类的事务方法时,由于未经过代理对象,事务会失效。​

        通常有以下失效的场景:

        场景一:事务传播行为配置错误​

        场景描述:当一个事务方法调用另一个事务方法时,若传播行为设置不合理,可能导致事务无法正常回滚。例如,在嵌套业务中使用PROPAGATION_REQUIRES_NEW时,内层事务提交后,外层事务回滚不会影响内层;若使用PROPAGATION_SUPPORTS,则方法会跟随当前事务(若不存在则不开启事务)。​

代码示例(错误):​

@Service
public class OrderService {@Autowiredprivate PaymentService paymentService;@Transactional(propagation = Propagation.REQUIRED)public void createOrder() {// 保存订单saveOrder();// 调用支付方法,传播行为为SUPPORTSpaymentService.makePayment();}
}@Service
public class PaymentService {@Transactional(propagation = Propagation.SUPPORTS)public void makePayment() {// 支付逻辑,若当前无事务则不开启事务updatePaymentStatus();// 模拟异常int i = 1 / 0;}
}

        问题分析:makePayment方法的传播行为为SUPPORTS,若createOrder的事务未生效(或传播行为不匹配),则支付操作不会在事务中执行,异常发生后无法回滚。​

        解决方法:根据业务需求选择合适的传播行为,如核心业务使用REQUIRED(默认值),确保方法在事务中执行。​

        场景二:异常被捕获但未重新抛出​

        场景描述:事务方法中若手动捕获了异常且未重新抛出,Spring 会认为事务执行成功,不会触发回滚。​

代码示例(错误):​

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Transactionalpublic void updateUserInfo() {try {userMapper.updateName(1, "newName");// 模拟异常int i = 1 / 0;} catch (Exception e) {// 仅捕获异常未处理log.error("更新失败", e);}}
}

        问题分析:异常被try-catch捕获后,未抛出到外层,Spring 无法感知异常,因此不会回滚updateName操作。​

        解决方法:捕获异常后重新抛出,或通过@Transactional(rollbackFor = Exception.class)指定回滚异常类型,并在外层处理。​

        场景三:方法访问权限问题​

        场景描述:Spring 事务基于 AOP 动态代理实现,若事务方法被private、final或static修饰,代理无法重写该方法,导致事务注解失效。​

代码示例(错误):​

@Service
public class ProductService {@Autowiredprivate ProductMapper productMapper;// private修饰的事务方法@Transactionalprivate void reduceStock(Long productId, int quantity) {productMapper.decreaseStock(productId, quantity);}public void processOrder(Long productId, int quantity) {reduceStock(productId, quantity); // 调用私有方法}
}

        ​问题分析:reduceStock为私有方法,Spring 无法生成代理方法,@Transactional注解失效,库存减少操作在异常发生时不会回滚。​

        解决方法:将事务方法修改为public修饰,且避免使用final或static。​

        场景四:未配置事务管理器​

        场景描述:Spring 事务的生效依赖于事务管理器(如DataSourceTransactionManager),若未在配置类中声明事务管理器,@Transactional注解将不起作用。​

        代码示例(错误配置):​

@Configuration
@MapperScan("com.example.mapper")
public class MyBatisConfig {@Beanpublic DataSource dataSource() {// 配置数据源HikariConfig config = new HikariConfig();config.setJdbcUrl("jdbc:mysql://localhost:3306/test");return new HikariDataSource(config);}
}

        问题分析:仅配置了数据源,未配置PlatformTransactionManager,Spring 无法管理事务。​

        解决方法:添加事务管理器配置:​

        场景五:同一类内方法自调用​

        场景描述:在同一个类中,非事务方法直接调用本类的事务方法时,由于调用的是原始对象(非代理对象),事务会失效。​

        代码示例(错误):​

@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;public void createOrder() {// 非事务方法调用本类事务方法saveOrder();}@Transactionalpublic void saveOrder() {orderMapper.insert(new Order());int i = 1 / 0; // 模拟异常}
}

问题分析:createOrder未被@Transactional修饰,调用saveOrder时使用的是当前类实例(非代理对象),事务注解失效,异常发生后订单数据仍会被插入。​

解决方法:​

(1)将事务方法拆分到另一个服务类中,通过依赖注入调用(推荐)。​

(2)自注入代理对象(需开启exposeProxy = true):​

        在这里,给出几个关于事务失效的排查建议​

(1)检查事务注解:确保方法被@Transactional修饰,且注解属性(如rollbackFor、propagation)配置正确。​

(2)验证代理模式:Spring 默认使用 JDK 动态代理(接口),若使用 CGLIB 代理需确保类未被final修饰,且依赖中包含 CGLIB 库。​

(3)查看异常处理:检查事务方法中是否有异常被捕获后未重新抛出,确保异常类型符合rollbackFor配置。​

(4)调试事务日志:在application.properties中添加日志配置logging.level.org.springframework.transaction=DEBUG,观察事务的开启、提交和回滚日志。​

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

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

相关文章

JavaScript 01 JavaScript 是什么

1.1 JavaScript 是什么JavaScript 是一门世界上最流行的脚本语言(基本所有平台的所有软件都会用到它)。“1994年,网景公司(Netscape)发布了Navigator浏览器0.9版。这是历史上第一个比较成熟的网络浏览器,轰动一时。但是&#xff0…

Bun v1.2.19发布,node_modules隔离,sql比node快6倍

大家好,我是农村程序员,独立开发者,行业观察员,前端之虎陈随易。我会在这里分享关于 独立开发、编程技术、思考感悟 等内容,欢迎关注。 技术群与交朋友请在个人网站联系我,网站 1️⃣:https://chensuiyi.me,网站 2️⃣:https://me.yicode.tech。 如果你觉得本文有用…

【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 主页布局实现

大家好,我是java1234_小锋老师,最近写了一套【NLP舆情分析】基于python微博舆情分析可视化系统(flaskpandasecharts)视频教程,持续更新中,计划月底更新完,感谢支持。今天讲解主页布局实现 视频在线地址: …

# 微调需要准备哪些环境配置?

微调需要准备哪些环境配置? 如果没有 GPU,即便是微调较小的大语言模型(LLMs),过程也会比较慢。如果你已经有了现成的 GPU,那就可以直接开工了。不过,并不是所有人都能负担得起 GPU—— 这种情况…

ClickHouse物化视图避坑指南:原理、数据迁移与优化

摘要ClickHouse物化视图通过预计算和自动更新机制,显著提升大数据分析查询性能,尤其适合高并发聚合场景。本文将深入解析其技术原理、生产实践中的优化策略,以及数据迁移的实战经验。一、物化视图核心概念ClickHouse的物化视图(Materialized …

Springboot3整合Elasticsearch8(elasticsearch-java)

1、Elasticsearch的JAVA客户端选择 Elasticsearch官方支持的客户端 客户端名称简介使用建议Elasticsearch Java API Client(新客户端)官方推荐的新客户端,基于 JSON Mapping(如 ElasticsearchClient 类),…

OpenCV 官翻8 - 其他算法

文章目录高动态范围成像引言曝光序列源代码示例图像说明结果色调映射图像曝光融合附加资源高级图像拼接 API(Stitcher 类)目标代码说明相机模型试用指南图像拼接详解 (Python OpenCV >4.0.1)stitching_detailed如何使用背景减除方法目标代码代码解析结…

2025年一区SCI-回旋镖气动椭圆优化算法Boomerang Aerodynamic Ellipse-附Matlab免费代码

引言 本期介绍一种新的元启发式算法——回旋镖气动椭圆优化算法Boomerang Aerodynamic Ellipse Optimizer (BAEO)。该优化器的灵感来自于飞行中的回旋镖的空气动力学行为,明确地建模了释放角和发射力如何塑造其轨迹。于2025年7月最新发表在JCR 1区,中科…

Custom SRP - Custom Render Pipeline

https://catlikecoding.com/unity/tutorials/custom-srp/custom-render-pipeline/ 1. 新建 Render Pipeline 任何内容的渲染,最终都是要由 unity 决定在哪里,什么时候,以哪些参数进行渲染。根据目标效果的复杂程度,决定渲染的过程…

C语言面向对象编程

1.内核通用链表一、什么是 list_head&#xff1f;list_head 是 Linux 内核中自己实现的一种 双向循环链表 的结构&#xff0c;定义在 <linux/list.h> 中。它设计得非常轻巧、灵活&#xff0c;广泛用于内核模块、驱动、进程调度、网络协议栈等。它的关键思想是&#xff1a…

Spring Boot+Redis Zset:三步构建高可靠延迟队列系统

系统设计架构图---------------- ----------------- ---------------- | | | | | | | 生产者 |------>| Redis ZSet |------>| 定时任务消费者 | | (添加延迟任务) | | (延…

MCP vs 传统集成方案:REST API、GraphQL、gRPC的终极对比

MCP vs 传统集成方案&#xff1a;REST API、GraphQL、gRPC的终极对比 &#x1f31f; Hello&#xff0c;我是摘星&#xff01; &#x1f308; 在彩虹般绚烂的技术栈中&#xff0c;我是那个永不停歇的色彩收集者。 &#x1f98b; 每一个优化都是我培育的花朵&#xff0c;每一个特…

SQL语句中锁的使用与优化

一、锁机制简介1.定义在数据库中&#xff0c;除了传统的计算资源&#xff08;如CPU、RAM、I/O等&#xff09;的争用以外&#xff0c;数据也是一种供需要用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题&#xff0c;锁冲突也是影响数据库并…

Linux笔记1——简介安装

操作系统给用户一个操作界面&#xff0c;用户通过操作界面使用系统资源Linux内核管理控制硬件&#xff0c;和硬件打交道SCSI&#xff08;盘&#xff09;sd**;第一个*表示磁盘顺序&#xff0c;第二个*表示分区。例如&#xff1a;sda\sdb\sdc,sda1,sda2NVMe&#xff08;盘&#x…

GoLand 部署第一个项目

前言&#xff1a;Go环境部署分为两种模式&#xff0c;一种是基于GOPATH部署&#xff08;老版本&#xff09;&#xff0c;另一种是基于Module部署&#xff08;新版本v1.11开始&#xff09;。GOPATH&#xff1a;需要配置GOPATH路径&#xff0c;将GOPATH目录视为工作目录&#xff…

Mosaic数据增强介绍

1. 核心概念与目标Mosaic 是一种在计算机视觉&#xff08;尤其是目标检测任务&#xff09;中非常流行且强大的数据增强技术。它最早由 Ultralytics 的 Alexey Bochkovskiy 在 YOLOv4 中提出并推广&#xff0c;后来被广泛应用于 YOLOv5, YOLOv7, YOLOv8 等模型以及其他目标检测框…

LINUX 722 逻辑卷快照

逻辑卷快照 lvcreate -L 128M -s -n lv1-snap /dev/vg1/lv1 lvs lvscan mount -o ro /dev/vg1/lv1 /mmt/lv1-snap dmsetup ls --tree 测试 lvs /dev/vg1/lv1-snap dd if/dev/zero of/uc1/test bs1M count40 lvs /dev/vg1/lv1-snap 问题 [rootweb ~]# cd /mnt [rootweb mnt]# m…

Springboot+vue个人健康管理系统的设计与实现

文章目录前言详细视频演示具体实现截图后端框架SpringBoot前端框架Vue持久层框架MyBaits成功系统案例&#xff1a;代码参考数据库源码获取前言 博主介绍:CSDN特邀作者、985高校计算机专业毕业、现任某互联网大厂高级全栈开发工程师、Gitee/掘金/华为云/阿里云/GitHub等平台持续…

数据结构 --栈和队链

一.栈的概念一种特殊的线性表&#xff0c;只能从固定的一端插入和删除元素。栈中元素遵循先进后出的原则。二.模拟实现public class MyStack {public int size;public int[] array;public MyStack(){array new int[10];}private void grow(){array Arrays.copyOf(array,array…

文档处理控件TX Text Control系列教程:使用 C# .NET 将二维码添加到 PDF 文档

PDF 文档通常是合同、发票、证书和报告的最终格式。尽管它们在设计上是静态的&#xff0c;但用户现在希望能够与它们交互、验证信息并直接从这些文件访问数字服务。这时&#xff0c;二维码就变得至关重要。 PDF 文档中的二维码将印刷或数字内容与动态在线体验连接起来。用户只需…