事务的传播行为解析(Transaction propagation: Required,RequiresNew,Nested)
propagation
1.Required
PROPAGATION_REQUIRED enforces a physical transaction, either locally for the current scope if no transaction exists yet or participating in an existing 'outer' transaction defined for a larger scope. This is a fine default in common call stack arrangements within the same thread (for example, a service facade that delegates to several repository methods where all the underlying resources have to participate in the service-level transaction).
PROPAGATION_REQUIRED强制执行物理事务,如果尚不存在当前事务,则在本地为当前范围执行,或参与为更大范围定义的现有“外部”事务。这是同一线程常用调用栈(例如,一个使用门面设计模式的服务被委派几种存储数据库的方法,所有基础资源都必须参与服务级事务中)中的优良默认设置。
When the propagation setting is PROPAGATION_REQUIRED, a logical transaction scope is created for each method upon which the setting is applied. Each such logical transaction scope can determine rollback-only status individually, with an outer transaction scope being logically independent from the inner transaction scope. Of course, in case of standard PROPAGATION_REQUIRED behavior, all these scopes will be mapped to the same physical transaction. So a rollback-only marker set in the inner transaction scope does affect the outer transaction's chance to actually commit (as you would expect it to).
当传播设置为PROPAGATION_REQUIRED时,将为应用该设置的每种方法创建一个逻辑事务作用域。每个此类逻辑事务作用域可以单独确定仅回滚(rollback-only)状态,而外部事务作用域在逻辑上与内部事务作用域无关。当然,在标准PROPAGATION_REQUIRED行为的情况下,所有这些范围都将映射到同一物理事务。因此,内部事务范围中设置的仅回滚标记确实会影响外部事务实际提交的机会(正如您期望的那样)。
However, in the case where an inner transaction scope sets the rollback-only marker, the outer transaction has not decided on the rollback itself, and so the rollback (silently triggered by the inner transaction scope) is unexpected. A corresponding UnexpectedRollbackException is thrown at that point. This is expected behavior so that the caller of a transaction can never be misled to assume that a commit was performed when it really was not. So if an inner transaction (of which the outer caller is not aware) silently marks a transaction as rollback-only, the outer caller still calls commit. The outer caller needs to receive an UnexpectedRollbackException to indicate clearly that a rollback was performed instead.
但是,在内部事务范围设置仅回滚(rollback-only)标记的情况下,外部事务尚未决定回滚本身,因此回滚(由内部事务范围默默触发)是未预料的。此时将引发相应的UnexpectedRollbackException。这是预期的行为,因此事务的调用方决不能被误导以假定在确实未执行提交的情况下执行该提交。因此,如果内部事务(外部调用方不知道)将事务默默地标记为仅回滚(rollback-only),外部调用方仍会调用commit。外部调用者需要接收一个UnexpectedRollbackException,以清楚地指示已执行回滚。
代码示例:
//deviceService外部事务Propagation.required @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRED) public void updateDeviceStatus(String string) { deviceMapper.updateDeviceStatus("20b5273ebeb84229a8c1e0d8b535974f", string); try { nestService.updateDeviceStatus("869aab5ad135491c95b90772d864034a", string); } catch (Exception e) { log.error("error", e); } }
//nestService内部事务 @Transactional(propagation = Propagation.REQUIRED) public void updateDeviceStatus(String s, String string) { deviceMapper.updateDeviceStatus(s, string); int i = 1 / 0; }
1.1,外部方法有事务注解 且 传播行为是propagation.required ,也有事务注解 且 传播行为是propagation.required。当内部方法或外部方法出现抛出异常时,无论外部方法是否捕获异常,内外事务都会回滚;
1.2,外部方法没有事务注解 ,内部方法也有事务注解且传播行为是propagation.required,当内部方法出现抛出异常时。无论外部方法是否捕获异常,只有内部方法回滚事务;
1.3,外部方法有事务注解且传播行为是propagation.required,内部方法没有事务注解。当内部方法出现抛出异常时,外部捕获异常,内外事务都不会回滚;
1.4,外部方法有事务注解且传播行为是propagation.required,内部方法没有事务注解。当内部方法出现抛出异常时,外部不捕获异常,内外事务都会回滚;
2.requiresNew
PROPAGATION_REQUIRES_NEW, in contrast to PROPAGATION_REQUIRED, always uses an independent physical transaction for each affected transaction scope, never participating in an existing transaction for an outer scope. In such an arrangement, the underlying resource transactions are different and, hence, can commit or roll back independently, with an outer transaction not affected by an inner transaction’s rollback status and with an inner transaction’s locks released immediately after its completion. Such an independent inner transaction can also declare its own isolation level, timeout, and read-only settings and not inherit an outer transaction’s characteristics.
与PROPAGATION_REQUIRED相比,PROPAGATION_REQUIRES_NEW始终对每个受影响的事务范围使用独立的物理事务,而从不参与外部范围的现有事务。 在这种安排中,基础资源事务是不同的,因此可以独立地提交或回滚,而外部事务不受内部事务回滚状态的影响,并且内部事务在完成后立即释放锁。 这样的独立内部事务还可以声明其自己的隔离级别,超时和只读设置,而不会继承外部事务的特征。
2.1,外部方法有事务注解且传播行为是propagation.required, 内部方法也有事务注解且传播行为是propagation.requiredNew。当内部方法出现抛出异常时,外部方法捕获异常,只有内事务会回滚;当内部方法抛出异常时,外部方法不捕获异常,那么内外事务都会回滚;
2.2,外部方法有事务注解 且 传播行为是propagation.required, 内部方法也有事务注解且传播行为是propagation.requiredNew。当外部方法出现抛出异常时,只有外部事务会回滚;
3. Nested
Understanding PROPAGATION_NESTED
PROPAGATION_NESTED uses a single physical transaction with multiple savepoints that it can roll back to. Such partial rollbacks let an inner transaction scope trigger a rollback for its scope, with the outer transaction being able to continue the physical transaction despite some operations having been rolled back. This setting is typically mapped onto JDBC savepoints, so it works only with JDBC resource transactions. See Spring’s DataSourceTransactionManager.
了解PROPAGATION_NESTED
PROPAGATION_NESTED使用具有多个保存点的单个物理事务,它可以回滚到该保存点。 这种部分回滚使内部事务范围触发其范围的回滚,尽管某些操作已回滚,但外部事务仍能够继续物理事务。 此设置通常映射到JDBC保存点,因此仅适用于JDBC资源事务。 请参阅Spring的DataSourceTransactionManager。
3.1,外部方法有事务注解且传播行为是propagation.required , 内部方法也有事务注解且传播行为是propagation.nested。当内部方法出现抛出异常时,外部方法捕获异常,只有内事务会回滚;当内部方法抛出异常时,外部方法不捕获异常,那么内外事务都会回滚;
3.2,外部方法有事务注解且传播行为是propagation.required , 内部方法也有事务注解且传播行为是propagation.nested。当外部方法出现抛出异常时,内外事务都会回滚;