1. 什么是事务
事务(Transaction)是在数据库系统中执行的一组操作,它们作为一个单元被执行。
事务具有以下四个属性,通常称为 ACID 属性:
- 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败,没有中间状态。
- 一致性(Consistency):事务在开始和结束时,数据库保持一致状态。
- 隔离性(Isolation):一个事务的执行不会受到其他事务的干扰,各个事务之间是相互独立的。
- 持久性(Durability):一旦事务提交,数据的更改是永久性的,即使系统发生故障也不会丢失。
2. 什么是传播行为
传播行为(Propagation Behavior)是在事务管理中定义事务如何在方法调用之间传播的机制。它决定了在调用一个事务方法时,是否应该在当前事务中执行,或者启动一个新事务,或者以非事务方式执行。
3.Spring 中事务的传播行为有哪些?
- PROPAGATION_REQUIRED:默认行为,加入当前事务或创建新事务。
- PROPAGATION_REQUIRES_NEW:总是创建新事务,挂起当前事务。
- PROPAGATION_SUPPORTS:支持当前事务,如果没有事务则以非事务方式执行。
- PROPAGATION_NOT_SUPPORTED:不支持事务,以非事务方式执行,挂起当前事务。
- PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务则抛出异常。
- PROPAGATION_MANDATORY:必须在事务中执行,如果没有事务则抛出异常。
- PROPAGATION_NESTED:在当前事务中执行,支持嵌套事务。
4. Spring 中不同传播行为在嵌套事务中的表现
4.1 PROPAGATION_REQUIRED
描述:PROPAGATION_REQUIRED 是默认的传播行为。如果当前存在事务,则加入当前事务;如果当前没有事务,则创建一个新的事务。
使用场景:适用于大多数场景。通常用于确保代码在事务上下文中运行,以确保操作的一致性和原子性。
@Service
public class OuterService {
@Autowired
private InnerService innerService;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
// 执行一些操作
innerService.innerMethod();
// 执行其他操作
}
}
@Service
public class InnerService {
@Transactional(propagation = Propagation.REQUIRED)
public void innerMethod() {
// 执行内部操作
}
}
表现:outerMethod 和 innerMethod 在同一个事务中执行。如果其中任何一个方法抛出异常,整个事务都会回滚。
• 外部方法抛出异常:内部方法会回滚,因为它们在同一个事务中。
• 内部方法抛出异常:外部方法会回滚,因为它们在同一个事务中。
4.2 PROPAGATION_REQUIRES_NEW
描述:PROPAGATION_REQUIRES_NEW 总是创建一个新的事务,如果当前存在事务,则挂起当前事务。
使用场景:适用于希望内外方法在各自独立的事务中运行的情况。例如,日志记录或需要确保独立提交的操作。
@Service
public class OuterService {
@Autowired
private InnerService innerService;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
// 执行一些操作
innerService.innerMethod();
// 执行其他操作
}
}
@Service
public class InnerService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {
// 执行内部操作
}
}
表现:innerMethod 在一个新的事务中执行,与 outerMethod 的事务是独立的。
• 外部方法抛出异常:内部方法不会回滚。因为内部方法是独立事务,已经提交。
• 内部方法抛出异常:外部方法不会回滚。因为它们在独立的事务中。
4.3 PROPAGATION_SUPPORTS
描述:PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,则以非事务方式执行。
使用场景:适用于既可在事务中执行,也可在非事务中执行的情况。一般用于只读操作或不依赖事务特性的操作。
@Service
public class OuterService {
@Autowired
private InnerService innerService;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
// 执行一些操作
innerService.innerMethod();
// 执行其他操作
}
}
@Service
public class InnerService {
@Transactional(propagation = Propagation.SUPPORTS)
public void innerMethod() {
// 执行内部操作
}
}
表现:如果 outerMethod 在事务中执行,innerMethod 也会参与同一个事务。如果 outerMethod 没有事务,innerMethod 会以非事务方式执行。
• 外部方法抛出异常:如果外部方法在事务中,内部方法会回滚;否则,不会回滚。
• 内部方法抛出异常:如果外部方法在事务中,外部方法会回滚;否则,不会回滚。
4.4 PROPAGATION_NOT_SUPPORTED
描述:PROPAGATION_NOT_SUPPORTED 以非事务方式执行,如果当前存在事务,则挂起当前事务。
使用场景:适用于不希望代码在事务上下文中运行的情况,例如查询操作或其他不需要事务控制的场景。
@Service
public class OuterService {
@Autowired
private InnerService innerService;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
// 执行一些操作
innerService.innerMethod();
// 执行其他操作
}
}
@Service
public class InnerService {
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void innerMethod() {
// 执行内部操作
}
}
表现:innerMethod 总是以非事务方式执行,即使 outerMethod 在事务中。
• 外部方法抛出异常:内部方法不会回滚,因为它以非事务方式执行。
• 内部方法抛出异常:外部方法不会回滚,因为它们在不同的上下文中。
4.5 PROPAGATION_NEVER
描述:PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
使用场景:适用于确保代码不在事务上下文中执行的情况。一般用于确保某些操作在非事务中进行。
@Service
public class OuterService {
@Autowired
private InnerService innerService;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
// 执行一些操作
innerService.innerMethod();
// 执行其他操作
}
}
@Service
public class InnerService {
@Transactional(propagation = Propagation.NEVER)
public void innerMethod() {
// 执行内部操作
}
}
表现:如果 outerMethod 在事务中调用 innerMethod,则抛出异常;如果没有事务,innerMethod 以非事务方式执行。
• 外部方法抛出异常:内部方法不会回滚,因为它以非事务方式执行。
• 内部方法抛出异常:外部方法不会回滚,因为它们在不同的上下文中。
4.6 PROPAGATION_MANDATORY
描述:PROPAGATION_MANDATORY 表示当前方法必须在一个现有的事务中运行。如果当前没有事务存在,那么会抛出异常。
使用场景:适用于确保代码必须在事务上下文中执行的情况,通常用于基础设施代码,强制要求调用者提供事务上下文。
@Service
public class OuterService {
@Autowired
private InnerService innerService;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
// 执行一些操作
innerService.innerMethod(); // 如果当前有事务,innerMethod 会在同一个事务中执行
// 执行其他操作
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void outerMethodWithoutTransaction() {
// 以非事务方式执行
innerService.innerMethod(); // 会抛出异常,因为 innerMethod 需要在事务中执行
}
}
@Service
public class InnerService {
@Transactional(propagation = Propagation.MANDATORY)
public void innerMethod() {
// 执行需要事务的操作
// 如果没有事务存在,将抛出异常
}
}
表现:如果 outerMethod 没有事务,调用 innerMethod 会抛出异常;如果有事务,innerMethod 会参与同一个事务。
• 外部方法抛出异常:内部方法会回滚,因为它们在同一个事务中。
• 内部方法抛出异常:外部方法会回滚,因为它们在同一个事务中。
4.7 PROPAGATION_NESTED
描述:PROPAGATION_NESTED 在当前事务中执行,支持嵌套事务。如果当前事务存在,那么 innerMethod 会在当前事务中创建一个嵌套事务。
使用场景:适用于需要嵌套事务的场景,允许部分操作回滚而不影响外部事务。
@Service
public class OuterService {
@Autowired
private InnerService innerService;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
// 执行一些操作
innerService.innerMethod();
// 执行其他操作
}
}
@Service
public class InnerService {
@Transactional(propagation = Propagation.NESTED)
public void innerMethod() {
// 执行内部操作
}
}
表现:innerMethod 在嵌套事务中执行。如果 innerMethod 抛出异常,只回滚到 innerMethod 的保存点,outerMethod 的事务可以继续执行。如果 outerMethod 抛出异常,整个事务(包括嵌套事务)都会回滚。
• 外部方法抛出异常:内部方法会回滚,因为它们在同一个主事务中。
• 内部方法抛出异常:外部方法不会回滚,只回滚内部方法的嵌套事务。
5. 总结
事务管理是保证数据一致性和原子性的重要机制,而 Spring 中的事务传播行为为开发者提供了灵活的事务控制选项。在嵌套事务的场景下,不同的传播行为对事务的管理有着不同的影响,从 PROPAGATION_REQUIRED 的默认行为,到 PROPAGATION_REQUIRES_NEW 的独立事务,再到 PROPAGATION_NESTED 的嵌套事务,每种传播行为都有其独特的应用场景和特点。
通过对比和理解不同传播行为的作用,开发者可以根据业务需求选择合适的事务管理策略,确保系统的可靠性和数据的完整性。