面试题答案
一键面试PROPAGATION_NESTED事务传播行为原理
- 基本原理:当一个方法被标记为
PROPAGATION_NESTED
时,如果当前存在事务,那么该方法将在一个嵌套事务中执行。嵌套事务是当前事务的一个子事务,它有自己的保存点(Savepoint)。如果嵌套事务回滚,只会回滚到它自己的保存点,而不会影响外部事务。只有当外部事务提交时,嵌套事务的修改才会真正持久化。如果外部事务回滚,嵌套事务也会跟着回滚。 - 与其他传播行为的区别:
- 与PROPAGATION_REQUIRED的区别:
PROPAGATION_REQUIRED
如果当前有事务则加入当前事务,如果没有则创建新事务。但它没有保存点概念,一旦事务内任何地方回滚,整个事务都会回滚。而PROPAGATION_NESTED
有保存点,嵌套事务回滚不影响外部事务(除了外部事务回滚会导致嵌套事务回滚)。 - 与PROPAGATION_REQUIRES_NEW的区别:
PROPAGATION_REQUIRES_NEW
总是创建一个新的独立事务,与当前事务完全隔离。而PROPAGATION_NESTED
是嵌套在当前事务内,依赖于外部事务的提交。
- 与PROPAGATION_REQUIRED的区别:
适用业务场景
- 数据备份或日志记录场景:比如在执行核心业务逻辑时,同时需要记录详细的操作日志到另一个表。日志记录操作可以放在一个
PROPAGATION_NESTED
事务中。如果核心业务出现问题回滚,日志记录仍然可以保留。 - 子流程可部分回滚场景:在一个复杂业务流程中,包含多个子流程,部分子流程失败时,希望只回滚子流程相关操作,而不影响主流程其他部分已经完成的操作。
代码示例
假设使用Spring框架,代码如下:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class TransactionService {
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
try {
// 外部事务开始
System.out.println("Outer method started");
innerMethod();
// 模拟外部事务中其他可能失败的操作
throw new RuntimeException("Outer method error");
} catch (Exception e) {
System.out.println("Outer method caught exception: " + e.getMessage());
}
}
@Transactional(propagation = Propagation.NESTED)
public void innerMethod() {
System.out.println("Inner method started");
// 这里进行一些数据库操作等
System.out.println("Inner method completed");
}
}
在上述代码中,outerMethod
使用PROPAGATION_REQUIRED
传播行为开启一个事务,innerMethod
使用PROPAGATION_NESTED
传播行为嵌套在outerMethod
的事务中。当outerMethod
抛出异常时,innerMethod
会回滚到自己的保存点,但innerMethod
之前的操作日志仍然会打印出来,体现了PROPAGATION_NESTED
的特性。