spring事务的传播机制

625 阅读4分钟

在Spring中,事务的传播行为(Transaction Propagation Behavior)决定了方法之间调用时,事务应该如何传递和处理。Spring共支持 7种 传播机制,每种都有不同的语义和适用场景。


✅ Spring 中的7种事务传播机制及示例

下面以统一格式说明这7种传播机制,并配合代码示例说明其使用场景以及回滚的情况。


1. Propagation.REQUIRED(默认)

  • 含义:如果当前存在事务,则加入该事务;如果没有事务,则新建一个事务。
  • 特点:这是最常用的传播行为,适用于大多数业务操作。
  • 回滚情况:内部方法抛异常未捕获,外部方法也会回滚。

示例:

@Transactional(propagation = Propagation.REQUIRED)
public void serviceA() {
    // 插入用户信息
    userDao.insertUser();
    
    // 调用serviceB
    serviceB();  // 在同一个事务中执行
}

@Transactional(propagation = Propagation.REQUIRED)
public void serviceB() {
    // 插入订单信息
    orderDao.insertOrder();

    if (someErrorCondition) {
        throw new RuntimeException("插入订单失败");
    }
}

结果serviceB() 抛出异常 → 整个事务(包括 serviceA() 的插入用户)都会回滚。


2. Propagation.SUPPORTS

  • 含义:如果当前存在事务,则加入事务;否则以非事务方式执行。
  • 适合:只读操作或对事务不敏感的操作。
  • 回滚情况:不会主动开启事务,也不会触发回滚。

示例:

@Transactional(propagation = Propagation.SUPPORTS)
public void queryData() {
    // 查询数据
    userDao.selectUserById(1L);
}

结果

  • 如果是事务上下文中调用:查询会参与事务。
  • 如果是非事务调用:则以非事务方式执行,不涉及回滚。

3. Propagation.MANDATORY

  • 含义:必须存在事务,否则抛出异常。
  • 适合:强制要求方法必须运行在事务中。
  • 回滚情况:由外部事务控制。

示例:

@Transactional(propagation = Propagation.MANDATORY)
public void updateWithMandatory() {
    userDao.updateUserInfo();
}

结果

  • 若无事务调用此方法 → 抛出 IllegalTransactionStateException
  • 若有事务调用 → 正常参与事务,外部事务回滚时也一起回滚。

4. Propagation.REQUIRES_NEW

  • 含义:不管当前是否存在事务,都新建事务,并挂起当前事务(如果有)。
  • 适合:需要独立事务的方法(如日志记录、审计等)。
  • 回滚情况:内部事务回滚不影响外部事务,但外部事务回滚会影响内部事务。

示例:

@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
    userDao.insertUser();

    try {
        innerMethod();  // 独立事务
    } catch (Exception e) {
        // 捕获异常后继续执行
    }

    otherDao.insertOther();  // 即使inner回滚,这里仍可提交
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void innerMethod() {
    logDao.insertLog();

    if (someErrorCondition) {
        throw new RuntimeException("日志插入失败");
    }
}

结果

  • innerMethod() 抛出异常 → 它自己的事务回滚,不影响 outerMethod() 的其他操作。
  • outerMethod() 回滚 → innerMethod() 也会被回滚(因为它是外层事务的一部分)。

5. Propagation.NOT_SUPPORTED

  • 含义:以非事务方式执行,如果当前存在事务,则暂停它。
  • 适合:性能优先的只读操作或无需事务的方法。
  • 回滚情况:没有事务,无法回滚。

示例:

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void fastQuery() {
    userDao.selectAllUsers();  // 不参与事务
}

结果

  • 即使是在事务中调用,这个方法也不会参与事务。
  • 数据库一致性可能不受保证。

6. Propagation.NEVER

  • 含义:不能在事务中执行,否则抛出异常。
  • 适合:明确禁止事务的方法。
  • 回滚情况:不会执行,直接抛异常。

示例:

@Transactional(propagation = Propagation.NEVER)
public void nonTransactionalMethod() {
    System.out.println("This should not be called in a transaction.");
}

结果

  • 如果在事务中调用 → 抛出 IllegalTransactionStateException
  • 否则正常执行

7. Propagation.NESTED

  • 含义:如果当前存在事务,则嵌套在其中作为一个子事务(通过保存点实现);否则新建事务。
  • 适合:部分回滚需求。
  • 回滚情况:内部事务可以独立回滚而不影响外部事务。

示例:

@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
    userDao.insertUser();  // 外部事务开始

    try {
        innerMethod();  // 嵌套事务
    } catch (Exception e) {
        // 可以选择只回滚 innerMethod 的操作
    }

    otherDao.insertOther();  // 继续执行
}

@Transactional(propagation = Propagation.NESTED)
public void innerMethod() {
    orderDao.insertOrder();

    if (someErrorCondition) {
        throw new RuntimeException("插入订单失败");
    }
}

结果

  • innerMethod() 抛出异常 → 只回滚到保存点,不影响 user 插入。
  • outerMethod() 抛出异常 → 全部回滚,包括 innerMethod() 的更改。

📝 总结对比表

传播行为当前无事务当前有事务是否新事务是否可回滚特点
REQUIRED新建事务加入已有事务默认值,最常用
SUPPORTS非事务执行加入已有事务可选事务
MANDATORY报错加入已有事务强制要求事务
REQUIRES_NEW新建事务挂起现有事务,新建事务独立事务,互不影响
NOT_SUPPORTED非事务执行挂起现有事务,非事务执行提高性能
NEVER非事务执行报错禁止事务
NESTED新建事务在当前事务内嵌套(保存点)否(子事务)是(局部)支持局部回滚