Spring事务行为
Spring事务行为
当一个具有NESTED传播属性的事务spring方法调用另一个具有REQUIRED传播属性的事务方法时,内部事务可以强制回滚外部逻辑事务。有人可以确认吗?
我想处理RuntimeException并且不回滚外部事务,例如:
@Transactional class A { @Autowired B b; @Autowired C c; void methodA() { // 外部事务,这不应该回滚,但当前出现UnexpectedRollbackException b.methodB(() -> c.methodC()); } } @Transactional(propagation = Propagation.NESTED) class B { void methodB(Runnable action) { // 内部嵌套事务 try{ action.run(); } catch (Exception e){ // 什么都不做 } } } @Transactional class C { void methodC() { // 内部必需的事务 throw new RuntimeException(); } }
Spring事务的行为是如何的?为什么会出现这种问题?问题的解决方法是什么?
在Spring框架中,事务的传播行为有多种选项,其中包括NESTED和REQUIRED。NESTED会在当前事务存在时在当前事务内创建一个新的子事务,否则会像REQUIRED一样创建一个新的事务。然而,需要注意的是,NESTED只有在JDBC驱动程序支持保存点(savepoints)时才会真正被支持。
如果没有已经存在的事务,那么在NESTED的情况下,事务的行为如下:
开始事务(begin)
执行A.doSomething()
执行B.doSomethingThatCausesException()
回滚事务(rollback)
如果已经存在一个事务,那么在NESTED的情况下,事务的行为如下:
开始事务(begin)- 在A的作用域之外被调用
保存点A_savepoint
执行A.doSomething()
执行B.doSomethingThatCausesException()
回滚到保存点A_savepoint(rollback A_savepoint)
需要注意的是,以上行为仅在JDBC驱动程序支持嵌套事务时才会发生,否则它将像第一种情况一样行为。因此,如果你的JDBC驱动程序不支持嵌套事务,那么在使用NESTED传播行为时,它将像REQUIRED一样行为。
我认为保存点会带来更多的麻烦,如果你将数据库操作作为一个原子操作来处理,那么你将避免许多潜在的麻烦。