事务异常:Transaction rolled back because it has been marked as rollback-only

博客详细解释了在Spring中遇到'Transaction rolled back because it has been marked as rollback-only'异常的原因。问题源于同一类内部方法调用不走代理,导致事务管理失效。作者通过示例代码展示了如何触发该异常,并说明了Spring事务关联拦截器的工作原理。当一个事务方法内调用另一个事务方法,捕获并处理了子方法的异常时,由于事务传播特性,会导致事务处理冲突,进而标记事务只能回滚,最终引发异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前经常报"Transaction rolled back because it has been marked as rollback-only"这个异常

字面意思是"事务回滚了,因为它被标记了必须回滚",最开始完全不懂事务的嵌套,每次出现这个错误都想知道为什么,但是总是不能重现,后面反复折腾终于弄明白了怎么回事。

之前不能重现的一个重要原因是:同一个类,内部方法调用不走代理,spring基于注解的事务是基于代理的,不走代理,被调用的方法就不受事务管理代码的控制,自然无法重现问题.

测试代码:

TestController

@Autowired
TestRollbackService testRollbackService;

@RequestMapping("/test1")
public void test1(){
    try{
        testRollbackService.test1();
    }catch(Exception e){
        e.printStackTrace();
    }
}

TestRollbackServiceImpl

@Autowired
StudentMapper studentMapper;

@Autowired
TestTransactionService testTransactionService;

@Transactional(rollbackFor = Exception.class)
public void test1(){
    Student studentSelect = new Student();
    studentSelect.setId(new Long(1));
    Student student = studentMapper.selectByPrimaryKey(studentSelect);
    try{
        testTransactionService.test2();
    }catch(Exception e){
        e.printStackTrace();
    }
}

TestTransactionServiceImpl

@Autowired
StudentMapper studentMapper;

@Transactional(rollbackFor = Exception.class)
public void test2(){
Student studentForInsert = new Student();
studentForInsert.setId(new Long(19));
studentForInsert.setName(“测试11”);
studentForInsert.setScore(new BigDecimal(69));
studentMapper.updateByPrimaryKey(studentForInsert);
System.out.println(1/0);
}
TestRollbackService.test1(方法A)中调用了TestTransactionService.test2(方法B),上述代码可以触发回滚异常的报错

两个方法都加了事务注解,并且两个方法都会受到到事务管理的拦截器增强,并且事务传播的方式都是默认的,也就是REQUIRED,当已经存在事务的时候就加入事务,没有就创建事务。这里A和B都受事务控制,并且是处于同一个事务的。

A调用B,A中抓了B的异常,当B发生异常的时候,B的操作应该回滚,但是A吃了异常,A方法中没有产生异常,所以A的操作又应该提交,二者是相互矛盾的。

spring的事务关联拦截器在抓到B的异常后就会标记rollback-only为true,当A执行完准备提交后,发现rollback-only为true,也会回滚,并抛出异常告诉调用者。

原文链接:https://blog.csdn.net/qq_38478903/article/details/88929207

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值