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的事务根本就没有生效。所以也不会出现异常。


版权声明:本文为weixin_40991408原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_40991408/article/details/129313606