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

本文探讨了在Spring框架中,事务嵌套与异常处理不当导致的Transactionrolledbackbecauseithasbeenmarkedasrollback-only错误。分析了错误产生的原因,提出了两种解决方案:一是确保内层事务异常时整体事务回滚;二是修改内层事务传播方式。

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

问题出现

最近在重构之前同事的代码,完成重构后对代码进行调试的过程中,出现了服务调用异常的错误,而不是在项目中我们自定义的异常错误信息,所以怀疑这是框架层面的错误,而非业务代码上的错误。

问题排查

通过排查日志发现,具体的错误信息是Transaction rolled back because it has been marked as rollback-only,很明显是一个和事务相关的错误。且通过对业务逻辑中日志答应状况的排查,发现,业务正确执行到了最后,但是最后进行事务提交的时候进行了错误。开启spring事务后,当代码正确执行时,spring会在事务的最后进行一次事务提交,说明这是一个事务提交时的错误。

问题分析

通过对代码的查阅发现改业务逻辑上存在事务嵌套的情况。
通过对异常栈的仔细排查,发现,内层事务在一定场景下抛出了异常,但是却被外层事务用try–catch接住了。于是在内层事务异常的情况下,外层事务继续执行了。

原因解释

当spring开启事务时,如果不修改propagation的参数,则默认是propagation.REQUIRED。即如果有没有事务则新启一个事务,如果已经存在事务则加入这个事务。
当内层事务异常的情况下,如果是这种传播方式,正常来讲是需要回滚的,但是spring知识给内层事务做了一个rollback的标记。所以当内层事务抛出的异常被外层try-----catch时,外层事务正常执行,但在最后提交的时候发现,内层被标记了rollbck,所以就会抛出Transaction rolled back because it has been marked as rollback-only这个异常信息。

解决方案

原场景,内层事务的异常被外层事务捕获,内层被标记rollback,而外层提交,最后事务提交校验时抛出Transaction rolled back because it has been marked as rollback-only异常

@Transactional(rollbackFor = Exception.class)
public void methodA(){
	insert();
	System.out.println(1 / 0);
}

@Transactional(rollbackFor = Exception.class)
public void methodB(){
	try{
		methodA();
	}catch(Exception e){
		System.out.println("有异常");
	}
}
可以分两种情况来解决这个异常
  • 如果我们需要内层异常的情况下,回滚整个事务,可以让内层事务抛出的异常被外层事务的try----catch处理,再抛出新的异常,或者外层不通过try—catch处理这个异常。
  • 当然如果内层事务没有复用过,只是在这个地方使用,直接把内层的事务去了,让他和外层合并成一个事务也能解决这个问题。
@Transactional(rollbackFor = Exception.class)
public void methodA(){
	System.out.println(1 / 0);
}

@Transactional(rollbackFor = Exception.class)
public void methodB(){
	try{
		insert();
		methodA();
	}catch(Exception e){
		throw new Exception("存在异常")
	}
}
  • 如果内层事务异常的情况下只回滚内层事务,修改内层事务的事务传播方式
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public void methodA(){
	System.out.println(1 / 0);
}

@Transactional(rollbackFor = Exception.class)
public void methodB(){
	try{
		insert();
		methodA();
	}catch(Exception e){
		System.out.println("有异常");
	}
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值