Transaction rolled back because it has been marked as rollback-only

maven 打包失败

一.问题描述:

业务逻辑上存在事务嵌套的情况。例如:方法methodA()中有methodB(),两个方法都有操作数据库的业务代码insert()。执行methodA后,在一定场景下抛出了异常,异常如下:

Transaction rolled back because it has been marked as rollback-only

代码如下:

@Service
public class A{
@Transactional(rollbackFor = Exception.class)
public void methodA(){
	try{
		methodB();
		insert();
	}catch(Exception e){
		System.out.println("异常抛出");
	}
 }
}

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

二.原因分析:

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

三.解决方法:

分三种种业务情况来处理这个问题。

第一种情况:
内层事务异常的情况下只回滚内层事务,但不影响外层事务提交。这时只要修改内层事务的事务传播方式,@Transactional注解内加上propagation = Propagation.REQUIRES_NEW就可以。
代码如下:

@Service
public class A{
@Transactional(rollbackFor = Exception.class)
public void methodA(){
	try{
		methodB();
		insert();
	}catch(Exception e){
		System.out.println("异常抛出");
	}
 }
}

@Service
public class B{
@Transactional(rollbackFor = Exception.class,,propagation = Propagation.REQUIRES_NEW)
public void methodB(){
	insert();
	System.out.println(1 / 0);
 }
}

第二种情况:
methodB方法不是通用的方法,内层异常的情况下,回滚全部事务,让内层事务抛出的异常被外层事务的try–catch处理,设置手动回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
或者外层不要try–catch处理,异常直接抛到最外层。
代码如下:

@Service
public class A{
@Transactional(rollbackFor = Exception.class)
public void methodA(){
	try{
		methodB();
		insert();
	}catch(Exception e){
		TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
	}
 }
}

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

第三种种情况:
methodB方法是通用的方法,只是在这个地方使用,那么直接把内层的事务去了,让它和外层合并成一个事务也能解决这个问题。
代码如下:

@Service
public class A{
@Transactional(rollbackFor = Exception.class)
public void methodA(){
	try{
		methodB();
		insert();
	}catch(Exception e){
		System.out.println("异常抛出");
	}
 }
}

@Service
public class B{
public void methodB(){
	insert();
	System.out.println(1 / 0);
 }
}

四.特殊情况:

methodA和methodB在同一个类中,那就不会出现Transaction rolled back because it has been marked as rollback-only这个问题。
代码如下:

@Service
public class A{
@Transactional(rollbackFor = Exception.class)
public void methodA(){
	try{
		methodB();
		insert();
	}catch(Exception e){
		System.out.println("异常抛出");
	}
 }
 
@Transactional(rollbackFor = Exception.class)
public void methodB(){
	insert();
	System.out.println(1 / 0);
 }
 }
}

本质区别在于:methodA调用了同一个类的方法methodA。

原因:因为注解的生效是通过代理模式实现的,同一个类下相互调用,被调用者是没法生成代理方法的,即method2的事务根本就没有生效。所以也不会出现异常。

《肖申克的救赎》

生命可以归结为一种简单的选择:要么忙于生存,要么赶着去死。

懦怯囚禁人的灵魂,希望可以感受自由。强者自救,圣者渡人。

希望是件美丽的东西,也许是最好的东西。美好的东西是永远不会死的。

每个人都是自己的上帝。如果你自己都放弃自己了,还有谁会救你?

《熔炉》

我们一路奋战,不是为了能改变世界,而是为了不让世界改变我们。

现实如水母,看似美好无害实质总是致命伤人。

我们来到世界上,都是孤独的旅行,即使身边有人相伴,最终也会各奔东西!

世界上最美丽最珍贵的,反而是听不见且看不清的,只有用心才能感受得到。

《教父》

人可以不断犯错,但绝不能犯要命的错。

不要憎恨你的敌人,那会影响你的判断力。

人并非生来就伟大,而是越活越伟大。

《活着》

人是为了活着本身而活着,而不是为了活着之外的任何事物而活着。

以笑的方式哭,在死亡的伴随下活着。

没有什么比时间更具有说服力了,因为时间无需通知我们就可以改变一切。

你的命是爹娘给的,你不要命了也得先去问问他们。

《我不是药神》

世界上只有一种病,穷病,这种病你没法治,你也治不过来。

人间最高贵的是善良,是对生命的致敬。

《指环王》

把手握紧,里面什么也没有;把手放开,你得到的是一切。

我宁愿和你共度凡人短暂的一生,也不愿一个人看尽这世界的沧海桑田。

20.幸福的家庭都是相似的,不幸的家庭各有各的不幸。

或许有一天,人类变得萎缩懦弱,舍弃朋友,断绝友谊,但今天决不会这样。
《饮食男女》

22.人生不能像做菜,把所有的材料都准备好了才下锅。

什么叫做“可惜”啊,要心中有个“惜”字儿,才知道可惜。

其实一家人,住在一个屋檐下,照样可以各过各的日子,可是从心里产生的那种顾忌,才是一个家之所以为家的意义。

《让子弹飞》

世界上本没有路,有了腿便有了路。

如果你活着,早晚都会死;如果你死了,你就永远活着。

赚钱嘛,不寒碜

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当出现 "Transaction rolled back because it has been marked as rollback-only" 的异常时,通常是因为事务在某个方法中被标记为只能回滚,但后续的代码却试图提交该事务,从而导致异常的抛出。 一个例子是在方法A中捕获了方法B抛出的异常,并继续执行后续的代码,最后正常提交事务。然而,由于AB使用同一个事务,在方法B执行时,该事务会被标记为rollback-only,然后方法A继续使用该事务并执行事务提交的操作,因此最终会抛出异常。 要解决这个问题,可以在方法A中将异常继续往上抛出,而不是在catch块中处理异常,这样事务就会正确地回滚。例如,在方法A的catch块中将异常重新抛出,或者将异常声明为方法A抛出的异常之一。 另外,还可以通过在方法B中使用@Transactional注解来确保方法B在出现异常时事务正确回滚,以避免这个异常的出现。 总之,"Transaction rolled back because it has been marked as rollback-only" 异常通常是由于事务在被标记为rollback-only后继续提交引起的,可以通过将异常继续往上抛出或使用@Transactional注解来解决这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [COS——R.log](https://download.csdn.net/download/ktc7000/4424623)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Transaction rolled back because it has been marked as rollback-only](https://blog.csdn.net/hingli/article/details/118415444)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘德华一不小心就打代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值