Spring的事务传播机制有哪些?

1 个回答

  • 楚华奕
    倾城倩影销魂态,如此佳人何处寻。
    Spring 提供了 **7 种事务传播机制**,用于控制在**方法嵌套调用时事务如何传播**。合理使用传播机制可以**确保事务的一致性和完整性**。 **默认传播机制**:`REQUIRED` ## **1. 7 种事务传播机制** ### **(1)`REQUIRED`(默认)** - **如果当前没有事务,则创建一个新事务。** - **如果当前已有事务,则加入该事务。** - **事务方法 A 调用事务方法 B,B 发生异常,则 A 和 B 都回滚。** - **最常用的事务传播方式。** **示例:** ```java @Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 业务逻辑 } ``` ✅ **适用于大多数情况,多个方法需要共享同一个事务。** ### **(2)`REQUIRES_NEW`** - **每次都会开启一个新事务,如果当前已有事务,则挂起当前事务。** - **方法 A 调用 B,B 发生异常,A 事务不受影响(即 A 不会回滚)。** **示例:** ```java @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodB() { // 业务逻辑 } ``` ✅ **适用于需要独立事务的情况,如:** - **记录操作日志(避免日志回滚)。** - **发送 MQ 消息(避免业务失败影响 MQ 发送)。** ### **(3)`SUPPORTS`** - **如果当前存在事务,则加入当前事务。** - **如果当前没有事务,则以非事务方式运行(普通方法)。** **示例:** ```java @Transactional(propagation = Propagation.SUPPORTS) public void methodC() { // 业务逻辑 } ``` ✅ **适用于可有可无事务的场景,如:** - **查询操作,既可以在事务中运行,也可以独立运行。** ### **(4)`NOT_SUPPORTED`** - **当前有事务,则暂停事务,以非事务方式运行。** - **适用于** **读库** **(防止读操作参与事务回滚)。** - **方法 A(事务)调用方法 B(非事务),B 失败不会影响 A。** **示例:** ```java @Transactional(propagation = Propagation.NOT_SUPPORTED) public void methodD() { // 读库查询,避免事务影响 } ``` ✅ **适用于读写分离场景,如** - **事务内执行的查询操作避免锁表。** - **方法最后一个步骤查询,防止因事务回滚影响查询。** ### **(5)`MANDATORY`** - **必须在已有事务的情况下运行,如果当前没有事务,则抛出异常。** **示例:** ```java @Transactional(propagation = Propagation.MANDATORY) public void methodE() { // 业务逻辑 } ``` ✅ **适用于必须在事务环境下运行的方法,通常用于**: - **确保方法只能由事务方法调用,不能独立运行。** ### **(6)`NEVER`** - **必须在无事务的情况下运行,如果当前有事务,则抛出异常。** **示例:** ```java @Transactional(propagation = Propagation.NEVER) public void methodF() { // 业务逻辑 } ``` ✅ **适用于不希望方法运行在事务环境中的情况,如**: - **某些高性能的查询操作(避免事务开销)。** ### **(7)`NESTED`** - **如果当前有事务,则在** **当前事务内创建嵌套事务**(使用 Savepoint)。** - **如果当前没有事务,则等同于 `REQUIRED`。** - **子事务 `rollback` 不影响父事务,父事务 `rollback` 会影响子事务。** **示例:** ```java @Transactional(propagation = Propagation.NESTED) public void methodG() { // 业务逻辑 } ``` ✅ **适用于**: - **局部事务回滚,而不影响整体事务。** ## **2. 事务传播机制的用法示例** 假设: - `methodA()` 需要事务。 - `methodB()` 在 `methodA()` 里调用,需要独立事务。 **示例** ```java @Service public class TransactionFooService { @Autowired private FooDao fooDao; @Transactional(propagation = Propagation.REQUIRED) public void methodA() throws Exception { fooDao.updateFoo(); // 执行数据库更新 } } @Service public class TransactionBarService { @Autowired private BarDao barDao; @Autowired private TransactionFooService transactionFooService; @Transactional(propagation = Propagation.REQUIRED) public void methodB() throws Exception { barDao.updateBar(); transactionFooService.methodA(); // methodA 加入 methodB 的事务 } } ``` - **如果 `methodA()` 或 `methodB()` 失败,整个事务回滚。** ## **3. `rollbackFor` 的作用** 默认情况下: - **`RuntimeException` 或 `Error` 触发事务回滚**。 - **`CheckedException`(如 `IOException`)不会回滚**。 如果希望 `CheckedException` 也回滚,可以使用 `rollbackFor`: ```java @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class) public void methodX() throws Exception { // 业务逻辑 } ``` ✅ **适用于需要回滚 `CheckedException` 的情况。** ## **4. 事务传播机制应用场景** | 传播方式 | 场景 | |---------|---------| | `REQUIRED` | **默认方式,最常用**,方法 A 调用方法 B,B 失败则 A 也回滚。 | | `REQUIRES_NEW` | **独立事务**,如**记录日志、发送 MQ,避免主事务失败影响子事务**。 | | `SUPPORTS` | **读操作,事务可有可无**,如**查询操作**。 | | `NOT_SUPPORTED` | **暂停事务,防止读操作加入事务**(如**读写分离**)。 | | `MANDATORY` | **强制有事务,否则抛异常**,如**必须在事务中执行的操作**。 | | `NEVER` | **必须无事务,否则抛异常**,如**性能要求高的查询**。 | | `NESTED` | **嵌套事务(Savepoint),适用于局部回滚**,如**部分回滚的业务**。 | ## **5. 场景题解答** **问:一个事务方法 `A()` 里包含** **读库方法 `B()`,`B()` 该用什么传播机制?** - **如果 `B()` 是最后一步**,用 `NOT_SUPPORTED`(防止读操作失败导致回滚)。 - **如果 `B()` 在中间步骤**,用 `REQUIRED`(需要回滚时确保一致性)。 ✅ **示例** ```java @Service public class ReadWriteService { @Transactional(propagation = Propagation.REQUIRED) public void writeOperation() { // 写库操作 } @Transactional(propagation = Propagation.NOT_SUPPORTED) public void readOperation() { // 读库操作(事务已暂停) } } ``` 📌 **这样,读操作不会受到事务回滚的影响,提高系统稳定性。** ## **6. 结论** 1. **默认使用 `REQUIRED`,推荐构建事务一致性。** 2. **`REQUIRES_NEW` 适用于独立事务(如日志、MQ)。** 3. **`NOT_SUPPORTED` 适用于读写分离(避免读操作回滚)。** 4. **`NESTED` 适用于局部回滚(使用 Savepoint)。** 5. **`rollbackFor = Exception.class` 可以让 `CheckedException` 也回滚。**
    发布于 2025-03-09 15:42 •IP属地 黑龙江
    举报
    评论
    收藏