spring事务管理UnexpectedRollbackException

在使用spring事务管理时,程序报如下:
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only


程序的代码为:
  serviceA.methiodA{
beforedone;
methodB();
try{
serviceB.methodB{}; //这里面有异常标记为回滚, doSetRollbackOnly(status);
}catch{
//捕获异常转到commit时,由于已经标记为要回滚, 回滚并抛出新异常

}
other done;
}

//传播:propagation 为 Required
原来是自己没有弄懂spring事务的机制。
这个方法被调用执行时,有两个点是被spring事务代理。serviceA.methodA(),serviceB.methodB(),这两个方法中只要有异常事件将回滚。
(其实因为事务嵌套,serviceA#methodA中有异常标记并直接回滚,serviceB#methodB中有异常只是标记回滚状态,在调用回serviceA#methodA中回滚)。 这个方法中serviceB#methodB有异常事务被标记为回滚,继续执行到serviceA.methodA(), 可是被methodA捕获了,也就不回滚了,一直执行到最后commit。在commit时spring会判断回滚标志,若有回滚标记,回滚并抛出UnexpectedRollbackException异常。

如何解决:
上面就是serviceA#methodA中的方法不被serviceB#methodB影响。想到两个方法好像都不是很好。

1. serviceB.methodB不声明为事务代理。
很多时候serviceB.methodB也被其他地方,是要事务管理的。这时候可以重写一个方法。
但是要注意这个方法中数据的一致性。

2. 和1一样也是重写一个serviceB.methodBNE,里面不抛出异常,也要注意这个方法中数据的一致性。感觉是一样的。

个人感觉在使用尽量不捕获异常,以保证事务一致性,如果有如上面的需求
(如给所有人奖励物品时,当中可能有人条件不足而抛出异常,为不影响下面的要捕获)
可以独立一个包出来专门做一个对多人操作的。而不是在同一个service写两个一样的方法,
导致混乱。
不捕获则在调用serviceB.methodB()时就回滚不会到commit那。

从这次错误中可以得到:
1.弄清楚被spring事务代理方法有哪些,这些方法有异常事务都将回滚
(不含this.methodB调用,动态代理导致)

2. 被代理的方法内部有异常抛出,事务都会标记为回滚,并在最外层调用那回滚。
嵌套事务若是REQUIRED_NEW新事务则在那个方法调用时直接回滚
如上面serviceA#methodA中直接回滚, serviceB#methodB则只标记

3.在事务提交serviceA.methodA(最外层)中
commit(TransactionStatus)在具体提交事务之前会检查rollBackOnly状态,
如果该状态在methodB中被设置,那么转而执行事务的回滚操作。
rollBackOnly状态没被设置,则执行正常的事务提交操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值