Java 为什么Spring Propagation=需要跨嵌套逻辑事务

Java 为什么Spring Propagation=需要跨嵌套逻辑事务,java,spring,transactions,Java,Spring,Transactions,似乎当一个具有嵌套传播的事务性spring方法调用另一个具有所需传播的事务性方法时,内部事务可以强制回滚外部逻辑事务 例如,如果事务性方法ClassA.methodA(其传播=必需)调用事务性方法ClassB.methodB(其传播=嵌套),后者反过来调用事务性方法ClassC.methodC(其传播=必需),则如果ClassC.methodC启动回滚,然后,由ClassA.methodA开始的外部逻辑事务如果试图提交,将得到一个意外的回滚异常 如果C失败,B拥有的逻辑嵌套事务应该被强制回滚,这

似乎当一个具有嵌套传播的事务性spring方法调用另一个具有所需传播的事务性方法时,内部事务可以强制回滚外部逻辑事务

例如,如果事务性方法ClassA.methodA(其传播=必需)调用事务性方法ClassB.methodB(其传播=嵌套),后者反过来调用事务性方法ClassC.methodC(其传播=必需),则如果ClassC.methodC启动回滚,然后,由ClassA.methodA开始的外部逻辑事务如果试图提交,将得到一个意外的回滚异常

如果C失败,B拥有的逻辑嵌套事务应该被强制回滚,这是有意义的,但是C拥有的逻辑事务,并且从B内部调用的逻辑事务本身不会影响A的逻辑事务,应该能够影响A的逻辑事务,这是没有意义的。这似乎造成了methodA不能将methodB视为黑盒的情况,因为从表面上看,方法B似乎不能影响a的事务,但取决于它内部的行为,它可能会违反嵌套事务边界。为什么这是可能的?为什么spring选择以这种方式实现它

下面是上面讨论的代码示例:

public class ClassA {
  private ClassB classB;
  @Transactional(propagation = Propagation.REQUIRED)
  public void methodA() {
    try {
      classB.methodB();
     } catch (RuntimeException re) {
       // do nothing we don't want to fail, but alas we will get an UnexpectedRollbackException
     }
  }
}

public class ClassB {
  private ClassC classC;
  @Transactional(propagation = Propagation.NESTED)
  public void methodB() {
      classC.methodC();
  }
}

public class ClassC {
  @Transactional(propagation = Propagation.REQUIRED)
  public void methodC() {
      // If this method weren't transactional this would just return to the save point created by method B
      // I Want to just fail the NESTED transaction, but alas I'm going to fail everything
      throw new RuntimeException("Oh, woe is me!");
  }
}

我不知道为什么会这样,但我找到了一个解决办法:

    public class ClassA {
        private ClassB classB;

        public void methodA() {
            try {
                classB.methodB();
            } catch (RuntimeException re) {
                // do nothing we don't want to fail, but alas we will get an UnexpectedRollbackException
            }
        }
    }

    public class ClassB {
        private ClassC classC;

        @Transactional(propagation = Propagation.NESTED)
        public void methodB() {
            classC.methodC();
        }
    }

    public class ClassC {
        private TransactionTemplate requiredTransaction = createRequiredTransactionTemplate();

        public void methodC() {
            if (TransactionSynchronizationManager.isActualTransactionActive()) {
                // We are already in transaction, do not wrap in transaction
                _methodC();
            } else {
                requiredTransaction.execute(cb -> {
                    _methodC();
                    return null;
                });
            }
        }

        private void _methodC() {
            throw new RuntimeException("Oh, woe is me!");
        }
    }


这是4岁。。你找到解决办法了吗?