对Spring的每种事务传播级别的应用场景和失效场景
好的,下面针对Spring的每种事务传播级别,详细说明其应用场景和失效场景,帮助更好地理解它们的实际使用。
1. REQUIRED(默认)
- 应用场景:
- 大多数业务方法,尤其是需要事务支持的操作。
- 例如:订单创建(主业务)和订单明细插入(子业务)需要在同一个事务中完成。
- 失效场景:
- 如果外部方法没有事务,内部方法也不会开启事务(取决于外部调用)。
- 如果外部方法抛出异常,整个事务会回滚,可能导致内部方法的数据操作失效。
2. REQUIRES_NEW
- 应用场景:
- 需要独立事务的操作,不受外部事务影响。
- 例如:日志记录、审计操作,即使主业务失败,日志仍需记录。
- 失效场景:
- 如果外部事务已经存在,内部方法会挂起外部事务,可能导致外部事务的锁等待或死锁。
- 如果内部方法抛出异常,外部事务不会回滚,但内部事务会回滚。
3. SUPPORTS
- 应用场景:
- 查询操作,不需要强制事务支持。
- 例如:读取数据,如果有事务则加入,没有则以非事务方式执行。
- 失效场景:
- 如果外部方法没有事务,内部方法也不会开启事务,可能导致数据不一致。
- 不适用于写操作,因为缺乏事务支持可能导致数据丢失。
4. NOT_SUPPORTED
- 应用场景:
- 不需要事务支持的操作,尤其是与事务冲突的操作。
- 例如:调用外部系统接口,或者执行一些不需要事务的批量处理。
- 失效场景:
- 如果外部方法有事务,内部方法会挂起外部事务,可能导致外部事务的锁等待或超时。
- 不适用于需要事务支持的写操作。
5. MANDATORY
- 应用场景:
- 强制要求必须在事务中执行的操作。
- 例如:某些核心业务方法,必须由其他事务方法调用。
- 失效场景:
- 如果外部方法没有事务,内部方法会抛出异常。
- 不适用于非事务调用的场景。
6. NEVER
- 应用场景:
- 强制要求不能在事务中执行的操作。
- 例如:某些只读操作,或者与事务冲突的操作。
- 失效场景:
- 如果外部方法有事务,内部方法会抛出异常。
- 不适用于需要事务支持的写操作。
7. NESTED
- 应用场景:
- 需要部分回滚的复杂业务逻辑。
- 例如:订单创建(主事务)和库存扣减(嵌套事务),如果库存扣减失败,只回滚库存操作,不影响订单创建。
- 失效场景:
- 如果数据库不支持保存点(Savepoint),则无法使用嵌套事务。
- 如果外部事务回滚,嵌套事务也会回滚。
总结对比表
传播级别 | 应用场景 | 失效场景 |
---|---|---|
REQUIRED | 大多数业务方法,需要事务支持 | 外部无事务时,内部方法也无事务 |
REQUIRES_NEW | 需要独立事务的操作(如日志记录) | 可能导致外部事务锁等待或死锁 |
SUPPORTS | 查询操作,不需要强制事务支持 | 外部无事务时,内部方法也无事务 |
NOT_SUPPORTED | 不需要事务支持的操作(如外部调用) | 挂起外部事务,可能导致锁等待或超时 |
MANDATORY | 强制要求必须在事务中执行的操作 | 外部无事务时,抛出异常 |
NEVER | 强制要求不能在事务中执行的操作 | 外部有事务时,抛出异常 |
NESTED | 需要部分回滚的复杂业务逻辑 | 数据库不支持保存点时无法使用 |
实际开发建议
- 默认使用REQUIRED:适用于大多数业务场景。
- REQUIRES_NEW用于独立操作:如日志记录、审计等。
- NESTED用于复杂业务:需要部分回滚时使用。
- 避免滥用NOT_SUPPORTED和NEVER:除非明确不需要事务支持。
- MANDATORY用于强制事务:确保方法必须在事务中调用。
好的,下面通过代码示例展示每种事务传播级别的失效场景,帮助你更直观地理解它们的行为。
1. REQUIRED(默认)
失效场景:外部方法没有事务,内部方法也不会开启事务。
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
// 外部方法没有事务
public void outerMethod() {
myRepository.save(new MyEntity("Outer"));
innerMethod(); // 内部方法也不会开启事务
}
@Transactional(propagation = Propagation.REQUIRED)
public void innerMethod() {
myRepository.save(new MyEntity("Inner"));
throw new RuntimeException("Inner method failed");
}
}
- 结果:
innerMethod
抛出异常,但由于外部方法没有事务,数据不会被回滚。
2. REQUIRES_NEW
失效场景:外部事务被挂起,可能导致锁等待或死锁。
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
myRepository.save(new MyEntity("Outer"));
innerMethod(); // 开启新事务,挂起外部事务
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {
myRepository.save(new MyEntity("Inner"));
throw new RuntimeException("Inner method failed");
}
}
- 结果:
innerMethod
抛出异常,内部事务回滚,但外部事务不受影响。如果innerMethod
持有锁,可能导致外部事务锁等待。
3. SUPPORTS
失效场景:外部方法没有事务,内部方法以非事务方式执行。
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
// 外部方法没有事务
public void outerMethod() {
myRepository.save(new MyEntity("Outer"));
innerMethod(); // 以非事务方式执行
}
@Transactional(propagation = Propagation.SUPPORTS)
public void innerMethod() {
myRepository.save(new MyEntity("Inner"));
throw new RuntimeException("Inner method failed");
}
}
- 结果:
innerMethod
抛出异常,但由于没有事务,数据不会被回滚。
4. NOT_SUPPORTED
失效场景:挂起外部事务,可能导致锁等待或超时。
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
myRepository.save(new MyEntity("Outer"));
innerMethod(); // 挂起外部事务,以非事务方式执行
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void innerMethod() {
myRepository.save(new MyEntity("Inner"));
throw new RuntimeException("Inner method failed");
}
}
- 结果:
innerMethod
抛出异常,内部操作不会被回滚,外部事务继续执行。如果innerMethod
执行时间过长,可能导致外部事务锁等待。
5. MANDATORY
失效场景:外部方法没有事务,内部方法抛出异常。
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
// 外部方法没有事务
public void outerMethod() {
myRepository.save(new MyEntity("Outer"));
innerMethod(); // 抛出异常
}
@Transactional(propagation = Propagation.MANDATORY)
public void innerMethod() {
myRepository.save(new MyEntity("Inner"));
}
}
- 结果:
innerMethod
抛出IllegalTransactionStateException
,因为外部方法没有事务。
6. NEVER
失效场景:外部方法有事务,内部方法抛出异常。
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
myRepository.save(new MyEntity("Outer"));
innerMethod(); // 抛出异常
}
@Transactional(propagation = Propagation.NEVER)
public void innerMethod() {
myRepository.save(new MyEntity("Inner"));
}
}
- 结果:
innerMethod
抛出IllegalTransactionStateException
,因为外部方法有事务。
7. NESTED
失效场景:数据库不支持保存点,嵌套事务无法使用。
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
myRepository.save(new MyEntity("Outer"));
innerMethod(); // 嵌套事务
}
@Transactional(propagation = Propagation.NESTED)
public void innerMethod() {
myRepository.save(new MyEntity("Inner"));
throw new RuntimeException("Inner method failed");
}
}
- 结果:如果数据库不支持保存点,
innerMethod
会回滚,同时外部事务也会回滚。
总结
通过以上代码示例,可以清晰地看到每种事务传播级别的失效场景:
- REQUIRED:外部无事务时,内部方法也无事务。
- REQUIRES_NEW:外部事务被挂起,可能导致锁等待。
- SUPPORTS:外部无事务时,内部方法以非事务方式执行。
- NOT_SUPPORTED:挂起外部事务,可能导致锁等待。
- MANDATORY:外部无事务时,抛出异常。
- NEVER:外部有事务时,抛出异常。
- NESTED:数据库不支持保存点时,无法使用。
希望这些代码示例对你有帮助!