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

深碍√TFBOYSˉ_ 2022-05-24 00:06 664阅读 0赞

环境:Spring Boot + @Transactional()
代码:

  1. @Service
  2. public class ServiceB {
  3. @Autowired
  4. private ServiceA a;
  5. @Transactional(rollbackFor = Exception.class)
  6. public void b(){
  7. try{
  8. a.a();
  9. }catch (Exception e){
  10. e.printStackTrace();
  11. }
  12. }
  13. }
  14. @Service
  15. public class ServiceA {
  16. @Autowired
  17. private UserMapper userMapper;
  18. @Transactional(rollbackFor = Exception.class)
  19. public void a() {
  20. userMapper.deleteByPrimaryKey(1L);
  21. System.out.println(1 / 0);
  22. }
  23. }

执行结果

  1. java.lang.ArithmeticException: / by zero
  2. at com.sunm.service.ServiceA.a(ServiceA.java:20)
  3. at com.sunm.service.ServiceA$$FastClassBySpringCGLIB$$a0ea4d65.invoke(<generated>)
  4. at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
  5. .........
  6. org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
  7. at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:873)
  8. at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:710)
  9. at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:533)
  10. at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304)
  11. at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
  12. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
  13. at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
  14. at com.sunm.service.ServiceB$$EnhancerBySpringCGLIB$$e3c261d4.b(<generated>)
  15. at com.sunm.test.ServiceTest.method(ServiceTest.java:21)
  16. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  17. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  18. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  19. at java.lang.reflect.Method.invoke(Method.java:498)
  20. at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
  21. at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
  22. at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
  23. at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
  24. at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
  25. at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
  26. at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
  27. at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
  28. at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
  29. at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
  30. at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
  31. at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
  32. at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
  33. at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
  34. at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
  35. at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
  36. at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
  37. at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
  38. at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
  39. at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
  40. at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
  41. at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
  42. at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
  43. at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
  44. at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
  45. at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

以上代码会出现Transaction rolled back because it has been marked as rollback-only异常。

改成以下代码

  1. @Service
  2. public class ServiceB {
  3. @Autowired
  4. private ServiceA a;
  5. public void b(){
  6. try{
  7. a.a();
  8. }catch (Exception e){
  9. e.printStackTrace();
  10. }
  11. }
  12. }

执行结果

  1. java.lang.ArithmeticException: / by zero
  2. at com.sunm.service.ServiceA.a(ServiceA.java:20)
  3. at com.sunm.service.ServiceA$$FastClassBySpringCGLIB$$a0ea4d65.invoke(<generated>)
  4. at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
  5. .........

不会出现rollback-only异常。

  这是因为a()方法继承了b()方法的事务,在a方法中出现了异常,需要回滚,此时rollbackOnly设置成true,b()方法在提交事务的时候,发现rollbackOnly是true,报rollback-only的异常;
下面是事务提交时候的判断
事务提交判断
  第二段代码中,方法b中没有事务,所以不会出现rollback-only异常,由此推断出只要方法a()和b()不是同一个事务,在异常catch时就不会出现rollback-only异常

  以下两种方式可以解决此异常

  • 方式一:

    @Service
    public class ServiceA {

    1. @Autowired
    2. private UserMapper userMapper;
    3. @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    4. public void a() {
    5. userMapper.deleteByPrimaryKey(1L);
    6. System.out.println(1 / 0);
    7. }

    }

方法a()重新指定新的事务,两个方法不是同一个事务,没有事务干扰

  • 方式二:

    @Service
    public class ServiceB {

    1. @Autowired
    2. private ServiceA a;
    3. @Transactional(rollbackFor = Exception.class)
    4. public void b(){
    5. try{
    6. a.a();
    7. }catch (Exception e){
    8. e.printStackTrace();
    9. throw new RuntimeException(e);
    10. }
    11. }

    }

外层方法b()catch异常之后,继续往外抛出

发表评论

表情:
评论列表 (有 0 条评论,664人围观)

还没有评论,来说两句吧...

相关阅读