当前位置: 首页 > news >正文

Spring 事务管理 Transaction rolled back because it has been marked as rollback-only

举个例子:
假设我们有一个服务类的方法A,它调用了方法B。方法B抛出了一个异常,但是方法A捕获了这个异常并没有重新抛出。但是,方法B的事务传播行为可能是REQUIRED,所以方法B会在同一个事务中执行。当方法B抛出异常时,事务被标记为回滚。然后方法A捕获了异常,没有重新抛出,那么方法A的事务拦截器在退出时会尝试提交事务,但是发现事务已经被标记为回滚,于是就会回滚事务并输出上述信息。

解决:

检查代码中是否有在事务方法中捕获了异常但没有正确处理的情况。如果希望事务回滚,通常应该在捕获异常后,将异常重新抛出(或者不再捕获异常,让异常自动抛出)。

如果确实需要捕获异常并且不想回滚事务,那么可以考虑将可能抛出异常的方法的事务传播行为设置为REQUIRES_NEW,这样它会在一个新的事务中执行,不会影响当前事务。

但是,请注意,REQUIRES_NEW会开启一个新事务,如果原事务已经存在,则会挂起原事务,这样方法B的异常就不会导致原事务回滚。

另一种情况是,可能你并不想在一个事务中运行整个方法链,那么可以考虑调整事务的边界,将不需要事务的方法排除,或者将事务的传播行为设置为NOT_SUPPORTED等。

典型代码场景

@Service
public class UserService {@Transactionalpublic void outerMethod() {try {innerMethod();  // 内层方法抛出异常// 其他业务逻辑...} catch (Exception e) {// 捕获异常,希望继续执行log.error("发生错误", e);}// 这里Spring会尝试提交事务,但事务已被标记为rollback-only}@Transactional(propagation = Propagation.REQUIRED)public void innerMethod() {// 业务操作...throw new RuntimeException("业务异常"); // 导致事务被标记为rollback-only}
}

解决方案

方案1:重新抛出异常(推荐)

@Transactional
public void outerMethod() {try {innerMethod();} catch (Exception e) {log.error("发生错误", e);throw e; // 重新抛出异常,让事务正常回滚}
}

方案2:使用不同的事务传播机制

@Service
public class UserService {@Transactionalpublic void outerMethod() {try {// 使用REQUIRES_NEW创建新事务innerMethodWithNewTransaction();} catch (Exception e) {log.error("内层方法失败,但外层事务继续", e);}// 外层事务可以正常提交}@Transactional(propagation = Propagation.REQUIRES_NEW)public void innerMethodWithNewTransaction() {// 这个方法的异常不会影响外层事务throw new RuntimeException("业务异常");}
}

方案3:手动控制事务边界

@Service
public class UserService {@Autowiredprivate TransactionTemplate transactionTemplate;public void outerMethod() {// 手动控制事务transactionTemplate.execute(status -> {try {innerMethod();return true;} catch (Exception e) {status.setRollbackOnly(); // 明确标记回滚log.error("事务回滚", e);return false;}});}
}

方案4:使用声明式事务控制

@Service
public class UserService {@Transactionalpublic void outerMethod() {innerMethod();// 让异常自然传播,不要捕获}// 指定回滚的异常类型@Transactional(rollbackFor = Exception.class)public void innerMethod() {// 业务逻辑}
}

预防措施

  1. 统一异常处理策略:在事务边界明确异常处理方式
  2. 合理使用传播机制
    • REQUIRED(默认):加入现有事务
    • REQUIRES_NEW:创建新事务
    • NESTED:嵌套事务
  3. 避免在事务方法中静默捕获异常
  4. 使用事务监听器:监控事务状态
// 事务事件监听
@Component
public class TransactionEventListener {@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)public void handleRollback(TransactionRolledBackEvent event) {log.warn("事务回滚: {}", event.getTransactionName());}
}
http://www.dtcms.com/a/582200.html

相关文章:

  • git不想被添加的文件加入到了列表中如何去掉
  • 网关开发笔记
  • 不备案怎么做淘宝客网站吗网站的视频怎么下载
  • 贵阳市住房和城乡建设部网站北京有几个区几个县
  • 【笔记】修复 ComfyUI 启动 ImportError: cannot import name ‘cached_download‘ 错误
  • 长沙网站优化页面学校网站建设工作
  • 昆明企业做网站黎城网站建设
  • 在vue3+uniapp+vite中挂载全局属性方法
  • 地理信息科学 vs 测绘工程:专业区别与就业前景
  • ​​Linux环境下的C语言编程(十六)
  • 淘宝购物返利网站开发基层建设杂志网站
  • 某多多 Redis 面试相关知识点总结
  • 【STM32】知识点介绍三:哈希算法详解
  • Effective STL第8条: 切勿创建包含auto_ptr的容器对象
  • 使用DrissionPage实现虚拟货币市场数据智能爬取
  • 零基础入门C语言之预处理详解
  • 做外汇门户网站重庆相亲网
  • 域名怎么绑定自己网站企业网站如何去做优化
  • Cursor 2.0 扩展 Composer 功能,助力上下文感知式开发
  • C语言应用实例:奋勇争先锋(贪心,qsort用法)
  • 机器学习数学知识温习(2)- 高斯-正态分布
  • 【FAQ】HarmonyOS SDK 闭源开放能力 — Push Kit
  • 济南网站建设 泉诺家装公司排名前十
  • 网站开发主要都做些什么佛山网站优化有
  • 机器人+工业领域=?
  • 网站三大标签优化中山企业网站建设
  • 关于网站开发书籍域名服务器有哪些
  • 27.java openCV4.x 入门-Imgproc之图像线性混合
  • 基于Logistic映射与Chen超混沌系统结合DNA分块编解码的图像加密技术
  • dy自动化遇到的滑动问题