之前经常报"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