对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 需要部分回滚的复杂业务逻辑 数据库不支持保存点时无法使用

实际开发建议

  1. 默认使用REQUIRED:适用于大多数业务场景。
  2. REQUIRES_NEW用于独立操作:如日志记录、审计等。
  3. NESTED用于复杂业务:需要部分回滚时使用。
  4. 避免滥用NOT_SUPPORTED和NEVER:除非明确不需要事务支持。
  5. 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会回滚,同时外部事务也会回滚。

总结

通过以上代码示例,可以清晰地看到每种事务传播级别的失效场景:

  1. REQUIRED:外部无事务时,内部方法也无事务。
  2. REQUIRES_NEW:外部事务被挂起,可能导致锁等待。
  3. SUPPORTS:外部无事务时,内部方法以非事务方式执行。
  4. NOT_SUPPORTED:挂起外部事务,可能导致锁等待。
  5. MANDATORY:外部无事务时,抛出异常。
  6. NEVER:外部有事务时,抛出异常。
  7. NESTED:数据库不支持保存点时,无法使用。

希望这些代码示例对你有帮助!

你可能感兴趣的:(对Spring的每种事务传播级别的应用场景和失效场景)