在SpringBoot中,事务回滚可以用注解@Transactional标识。
Spring声明式事务管理默认对非检查型异常和运行时异常进行事务回滚,而对检查型异常则不进行回滚操作。
1、非检查型异常一般继承自Error或者RuntimeException
2、检查型异常一般指继承自Exception的异常
在实际使用过程中,可以自由指定那种异常需要进行事务回滚,一般为以下几种:
1、 让checked例外也回滚: @Transactional(rollbackFor=Exception.class)
2、 让unchecked例外不回滚: @Transactional(noRollbackFor=RunTimeException.class)
3 、不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED)
,或者不添加
注意: 如果你的异常被手动try{}catch{}
了,事务则不会回滚,系统会认为你已经手动进行了异常处理,如果想让事务回滚必须往外抛throw Exception
。
在实际使用过程中,有的事务回滚没有生效,这时候需要知道Spring中一个关于事务使用的规则。在同一个类中,一个没有带事务的方法中调用一个带事务的方法时,这个事务回滚不会生效。如下代码所示。
public class M {
public void a(D d) {
try {
System.out.println(d.getA());
b(d);
System.out.println("a--" + d.getA());
}catch (Exception e){
System.out.println("a--" + d.getA());
}
}
@Transactional(rollbackFor = Exception.class)
public void b(D d) {
System.out.println(d.getA());
d.setA(10);
int c = 2;
c = c / 0;
}
}
在上述代码中,a()方法不带事务且调用一个带事务的方法,结果在b()方法执行时,c = c / 0
会抛出出书不能为零的异常,正常情况下事务会回滚,也就是实例d中a的值应该回滚到设置为10之前。但是结果表明没有,也就是事务回滚没有生效。
解决办法
1、将无事务方法和有事务方法不要放在同一个类中。
在动态代理机制中,一次操作,proxy不会重复代理一个对象两次,基于代理的method.invoke...方法,无事务方法调用有事务方法时,即使加了事务注解@Transaction也不会生效。
2、获取被代理对象的proxy,让代理对象调用事务方法。
首先在项目启动类上添加动态代理事务注解 @EnableAspectJAutoProxy(exposeProxy = true)
在调用事务方法时,使用AopContext.currentProxy()
获取被代理对象的proxy,让后用proxy调用事务方法。代码如下:
(M)AopContext.currentProxy().b(d)
;