java中事务@Transaction的正确使用和触发回滚机制【经典】

@Transactional(rollbackFor=Exception.class) 的作用

1.1 说明

|-------------------------------------------------------------------------------------------------|
| @Transactional(rollbackFor = Exception.class) public void updateStock(Product targetProduct) {} |

作用:

1.开启数据库事务(Transaction)

2.强制对所有异常进行回滚:明确告诉 Spring:"只要方法抛出任何 Exception(包括 IOException、自定义业务异常等),都必须回滚事务!"

二****触发事务回滚机制

2.1说明

Spring 的声明式事务(@Transactional)是通过AOP代理实现的。它的回滚机制依赖于方法执行过程中是否抛出异常并传递到代理层。

✅ 会回滚的情况:方法内部抛出异常,并且这个异常没有被捕获,或者被捕获后重新抛出,最终导致方法以异常形式结束。

❌ 不会回滚的情况:方法内部使用try-catch捕获了所有异常,并在catch块中吞掉异常(不抛出),使得方法正常结束(return)。

三 反例说明

3.1 反例吞并异常,无法回滚

即使 applyForCheckEdit 抛出了 SQLException 或其他 Exception,你的 catch 块只是记录日志、放一个错误码到 resultMap,然后让方法正常返回。

Spring 的事务代理看到的是:"这个方法成功执行完了,返回了一个 Map",根本不知道中间出过错。因此,事务会被提交(commit),而不是回滚!

后果:如果 applyForCheckEdit 执行了一半(比如更新了 A 表,但在更新 B 表时出错),由于事务被提交,会导致数据不一致。

结论:**这段代码中的 @Transactional(rollbackFor = Exception.class) 不会生效,事务不会回滚。**只要你在 catch 块里"吃掉"了异常,事务就永远不会回滚。

3.2 解决办法

3.2.1 方案1:不进行try catch捕获,原生抛出db异常,spring捕获触发回滚

如果你希望任何错误都导致整个批量操作回滚,就不要用 try-catch 包裹数据库操作:

3.2.2 方案2:捕获后重新抛出(保留自定义处理逻辑)

如果你确实需要在 catch 中记录日志或做清理,但又希望回滚,必须重新抛出异常:

注意:一旦你 throw 了,调用方就需要处理这个异常,不能再通过返回 Map 判断成功与否。

相关推荐
Gofarlic_oms14 小时前
利用API实现ANSYS许可证管理自动化集成
运维·服务器·开发语言·matlab·自动化·负载均衡
AI+程序员在路上5 小时前
VS Code 完全使用指南:下载、安装、核心功能与 内置AI 编程助手实战
开发语言·人工智能·windows·开源
invicinble6 小时前
这里对java的知识体系做一个全域的介绍
java·开发语言·python
catchadmin6 小时前
使用 PHP TrueAsync 改造 Laravel 协程异步化的可行路径
开发语言·php·laravel
wbs_scy6 小时前
【Linux 线程进阶】进程 vs 线程资源划分 + 线程控制全详解
java·开发语言
ss2736 小时前
食谱推荐系统功能测试如何写?
java·数据库·spring boot·功能测试
AI人工智能+电脑小能手6 小时前
【大白话说Java面试题】【Java基础篇】第15题:JDK1.7中HashMap扩容为什么会发生死循环?如何解决
java·开发语言·数据结构·后端·面试·哈希算法
try2find7 小时前
打印ascii码报错问题
java·linux·前端
014-code7 小时前
CompletableFuture 实战模板(超时、组合、异常链处理)
java·数据库
Nicander7 小时前
多数据源下@transcation事务踩坑
java·后端