Home
img of docs

解析 Spring 中用于事务管理的核心注解 @Transactional,以及在代码中捕获异常时,该注解的作用如何变化。

chou403

/ Spring

/ c:

/ u:

/ 5 min read


Spring事务管理注解用的哪个?如果代码里捕获了异常,这个注解还有用么

在 Spring 中,事务管理通常通过 @Transactional 注解来实现。@Transactional 注解用于声明方法或类中的所有方法都在事务上下文中执行。Spring 事务管理器会自动处理这些方法的事务边界(即事务的开始和结束)。

使用 @Transactional 注解

基本使用

@Transactional 注解放在类上或方法上,以声明它们应在事务上下文中执行:

   import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Transactional
    public void createUser(User user) {
        // 方法体中的代码将在事务中执行
    }
}
高级使用

@Transactional 注解提供了一些属性来控制事务行为:

  • propagation:定义事务的传播行为,例如 REQUIRED(默认值),REQUIRES_NEW 等。
  • isolation:定义事务的隔离级别,例如 READ_COMMITTED,REPEATABLE_READ 等。
  • timeout:定义事务的超时时间(秒)。
  • readOnly:如果为 true,表示事务只读。
  • rollbackFor:定义哪些异常会触发事务回滚。
  • noRollbackFor:定义哪些异常不会触发事务回滚。
   @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, timeout = 30, readOnly = false, rollbackFor = {Exception.class})
public void createUser(User user) {
    // 方法体中的代码将在事务中执行
}

异常处理对事务的影响

Spring 的默认事务管理策略是在方法抛出未检查异常(RuntimeException 或 Error)时回滚事务。受检异常(Checked Exception)不会触发事务回滚,除非明确配置。

捕获异常对事务的影响

如果代码捕获了异常,并且没有重新抛出异常,事务管理器将不会检测到异常,也不会触发回滚。如下示例:

   @Transactional
public void createUser(User user) {
    try {
        // 业务逻辑
    } catch (Exception e) {
        // 捕获异常,事务不会回滚
        e.printStackTrace();
    }
}

在这种情况下,即使发生异常,由于异常被捕获,事务也不会回滚。要解决这个问题,可以显式地回滚事务:

显式回滚事务
  1. 使用 TransactionAspectSupport:

       import org.springframework.transaction.interceptor.TransactionAspectSupport;
    
    @Transactional
    public void createUser(User user) {
        try {
            // 业务逻辑
        } catch (Exception e) {
            // 手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            e.printStackTrace();
        }
    }
  2. 重新抛出异常:

    另一种方法是在捕获异常后重新抛出,这样事务管理器可以检测到异常并回滚事务:

       @Transactional
    public void createUser(User user) {
        try {
            // 业务逻辑
        } catch (Exception e) {
            // 重新抛出异常,触发回滚
            throw new RuntimeException(e);
        }
    }
  3. 指定 rollbackFor 属性:

    如果希望在受检异常发生时也回滚事务,可以使用 rollbackFor 属性:

       @Transactional(rollbackFor = Exception.class)
    public void createUser(User user) {
        try {
            // 业务逻辑
        } catch (Exception e) {
            // 捕获受检异常
            e.printStackTrace();
            throw e; // 重新抛出异常,触发回滚
        }
    }

总结

  • @Transactional 注解 用于声明方法或类中的所有方法在事务上下文中执行。
  • 异常捕获对事务的影响: 默认情况下,未检查异常会触发事务回滚,但受检异常不会。捕获异常会阻止事务管理器检测到异常,从而阻止事务回滚。
  • 显式回滚事务: 可以使用 TransactionAspectSupport 进行手动回滚,或在捕获异常后重新抛出异常,确保事务管理器检测到异常并回滚事务。