事务的传播行为(Propagation)定义了一个事务方法在被调用时如何与已有的事务进行交互。Spring 提供了多种传播行为,常用的包括 PROPAGATION_REQUIRED
、PROPAGATION_REQUIRES_NEW
、PROPAGATION_NESTED
等。每种传播行为的含义略有不同,具体表现为方法如何参与事务的传播。
下面通过 Java 代码示例来展示几种常见的事务传播行为的使用。
1. PROPAGATION_REQUIRED
(默认行为)
PROPAGATION_REQUIRED
是最常用的事务传播行为,表示如果当前没有事务,则新建一个事务;如果当前存在事务,则加入到该事务中。
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 执行数据库操作
System.out.println("Executing methodA");
// 调用methodB,它会加入到当前的事务中
methodB();
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
// 执行数据库操作
System.out.println("Executing methodB");
}
}
解释:
methodA
被@Transactional(propagation = Propagation.REQUIRED)
注解标注,表示它会在当前事务中执行。如果当前没有事务,它会创建一个新事务。methodA
内部调用了methodB
,methodB
也使用了@Transactional(propagation = Propagation.REQUIRED)
注解,因此methodB
会加入到methodA
的事务中,而不会开启一个新事务。
2. PROPAGATION_REQUIRES_NEW
PROPAGATION_REQUIRES_NEW
表示无论当前是否有事务,都会新建一个事务,且当前事务会被挂起,直到新事务完成后才会恢复。
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 执行数据库操作
System.out.println("Executing methodA");
// 调用methodB,它会新建一个事务
methodB();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 执行数据库操作
System.out.println("Executing methodB in a new transaction");
}
}
解释:
methodA
使用了Propagation.REQUIRED
,所以它会在当前事务中执行。methodB
使用了Propagation.REQUIRES_NEW
,所以它会启动一个新的事务,并挂起当前的事务。methodA
会等待methodB
完成,之后继续执行。
3. PROPAGATION_NESTED
PROPAGATION_NESTED
表示如果当前存在事务,则嵌套一个事务;如果当前没有事务,则与 REQUIRED
行为一致,创建一个新事务。嵌套事务支持回滚仅对当前嵌套的事务,不会影响外部事务。
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 执行数据库操作
System.out.println("Executing methodA");
// 调用methodB,它会嵌套一个事务
methodB();
}
@Transactional(propagation = Propagation.NESTED)
public void methodB() {
// 执行数据库操作
System.out.println("Executing methodB in a nested transaction");
// 模拟抛出异常,回滚methodB的事务,但不会影响methodA
throw new RuntimeException("Exception in methodB");
}
}
解释:
methodA
使用Propagation.REQUIRED
,在外部事务中执行。methodB
使用Propagation.NESTED
,会在当前的事务中启动一个嵌套事务。如果methodB
抛出异常,只有methodB
的事务会回滚,methodA
的事务(外部事务)则不会受到影响。
4. PROPAGATION_SUPPORTS
PROPAGATION_SUPPORTS
表示如果当前存在事务,则加入到该事务中;如果没有事务,则以非事务的方式执行。
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 执行数据库操作
System.out.println("Executing methodA");
// 调用methodB,它不会开启新的事务,如果没有事务会以非事务方式执行
methodB();
}
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() {
// 执行数据库操作
System.out.println("Executing methodB with SUPPORTS propagation");
}
}
解释:
methodA
使用Propagation.REQUIRED
,如果当前没有事务,它会新建一个事务。methodB
使用Propagation.SUPPORTS
,如果当前有事务,methodB
会加入到该事务中。如果当前没有事务,则methodB
会以非事务的方式执行。
5. PROPAGATION_MANDATORY
PROPAGATION_MANDATORY
表示当前方法必须在一个已经存在的事务中执行,如果当前没有事务,抛出异常。
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 执行数据库操作
System.out.println("Executing methodA");
// 调用methodB,methodB必须在一个已存在的事务中执行
methodB();
}
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() {
// 执行数据库操作
System.out.println("Executing methodB with MANDATORY propagation");
}
}
解释:
methodA
使用Propagation.REQUIRED
,因此它可以开启一个新的事务或加入到现有事务中。methodB
使用Propagation.MANDATORY
,这意味着它必须在一个已经存在的事务中执行。如果没有事务,methodB
会抛出异常。
6. PROPAGATION_NEVER
PROPAGATION_NEVER
表示当前方法不能在事务中执行,如果当前有事务,抛出异常。
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
// 执行数据库操作
System.out.println("Executing methodA");
// 调用methodB,methodB不能在事务中执行
methodB();
}
@Transactional(propagation = Propagation.NEVER)
public void methodB() {
// 执行数据库操作
System.out.println("Executing methodB with NEVER propagation");
}
}
解释:
methodA
使用Propagation.REQUIRED
,如果当前没有事务,它会新建一个事务。methodB
使用Propagation.NEVER
,这表示methodB
不能在事务中执行。如果当前有事务,methodB
会抛出异常。
总结
Spring 的事务传播行为可以用来控制方法如何参与已有的事务,具体的传播行为决定了事务的启动、挂起、嵌套等特性。通过合理选择传播行为,可以实现不同的事务管理策略,适应不同的业务需求。
常用的事务传播行为:
PROPAGATION_REQUIRED
: 默认行为,支持当前事务或创建新事务。PROPAGATION_REQUIRES_NEW
: 创建新事务,挂起当前事务。PROPAGATION_NESTED
: 嵌套事务,支持事务回滚。PROPAGATION_SUPPORTS
: 如果当前有事务,则加入当前事务;如果没有事务,则以非事务方式执行。PROPAGATION_MANDATORY
: 必须在当前事务中执行,否则抛出异常。PROPAGATION_NEVER
: 不能在事务中执行,如果有事务则抛出异常。