wangguangwu
wangguangwu
发布于 2024-08-14 / 29 阅读
0
0

Spring 中事务的传播行为

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 的嵌套事务,每种传播行为都有其独特的应用场景和特点。

通过对比和理解不同传播行为的作用,开发者可以根据业务需求选择合适的事务管理策略,确保系统的可靠性和数据的完整性。


评论