Skip to content

事务

@Transactional注解

  • 方法可见性@Transactional注解应用于公有方法上。如果注解在非公有方法上,事务可能不会生效
  • 异常处理:默认情况下,只有运行时异常(非受检异常)会导致事务回滚。如果需要受检异常(例如IOException)也触发回滚,需要在注解中明确指定
  • 事务传播行为:默认传播行为是REQUIRED,如果当前没有事务,则创建一个新事务,如果有,则加入当前事务。根据业务需求,可能需要设置不同的传播行为
  • 事务配置:确保事务管理器正确配置,并且注解驱动的事务管理已经开启(通常通过@EnableTransactionManagement注解)
  • 自调用问题:自调用(即一个类中的非事务方法调用本类中的事务方法)可能导致事务注解失效

事务传播级别Propagation

传播级别应用场景调用时存在事务调用时无事务是否新建事务注意事项
REQUIRED电商下单(订单创建+库存扣减需原子性),转账操作(A账户扣款+B账户入账)加入当前事务创建新事务按需创建默认级别,但需避免事务方法执行时间过长(如循环调用)
SUPPORTS商品列表查询(可适应事务/非事务环境),用户信息读取(低一致性要求)加入当前事务非事务执行非事务执行时可能读到脏数据(需结合业务容忍度)
MANDATORY资金结算(必须依赖上游事务) ,权限校验(需在事务中记录操作日志)加入当前事务抛出异常适用于底层工具类方法(如审计日志),强制调用方开启事务
REQUIRES_NEW异步任务触发(如短信发送,需独立提交) ,操作日志记录(避免主事务回滚影响日志)挂起当前事务,创建新事务创建新事务是(完全独立)新事务独立提交,但可能导致锁竞争(如并发日志写入需加分布式锁)
NOT_SUPPORTED发送站内通知(非核心操作) ,写入本地缓存(避免事务锁阻塞)挂起当前事务,非事务执行非事务执行强制脱离事务,但需注意非事务执行的线程安全问题(如缓存更新)
NEVER加载静态配置(如读取本地JSON文件) ,健康检查(仅查询服务状态)抛出异常非事务执行严格限制事务上下文,适用于工具类初始化方法
NESTED批量导入数据(单条失败跳过,继续处理) ,复杂计算中间结果保存(可回滚部分步骤)嵌套事务(基于保存点)创建新事务(行为同REQUIRED)按需创建(逻辑嵌套)仅Oracle等支持保存点的数据库有效,MySQL需改用REQUIRES_NEW+补偿机制
  • 优先默认(REQUIRED):适用于80%的增删改操作
  • 读操作优化:对查询方法使用SUPPORTSNOT_SUPPORTED,结合readOnly=true提升性能
  • 事务隔离性REQUIRES_NEWNESTED的选择需权衡数据库兼容性和业务需求
  • 分布式事务:跨服务调用时(如订单+库存服务),避免依赖本地事务传播级别,改用Seata等方案

自调用场景

@Transactional注解实际上是应用了AOP代理。当外部方法调用带有@Transactional注解的方法时,Spring AOP会在方法执行前启动事务,并在方法执行结束后提交或回滚事务

在自调用场景中ServiceA.java

java
public class ServiceA {

    public void methodA() {
        // ... do something
        methodB(); // 自调用
        // ... do something else
    }

    @Transactional
    public void methodB() {
        // ... transactional operations
    }
}

methodA()直接调用methodB(),它不是通过Spring AOP代理调用的,而是直接在同一个对象实例上调用的Java方法,因此,Spring AOP代理无法截获这个调用,也就无法应用事务管理

注入自身

通过Spring容器注入自身代理,然后通过代理调用事务方法

ServiceA.java

java
public class ServiceA {

    @Autowired
    private ServiceA self;

    public void methodA() {
        // ... do something
        self.methodB(); // 通过代理调用
        // ... do something else
    }

    @Transactional
    public void methodB() {
        // ... transactional operations
    }
}

self.methodB()是通过Spring AOP代理调用的,因此事务注解会生效

手动管理事务

配置类

注入对应的对象TransactionTemplate,新增配置类TransactionConfig.java

java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;

@Configuration
public class TransactionConfig {

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Bean
    public TransactionTemplate transactionTemplate() {
        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
        // 设置事务传播行为为REQUIRED,表示如果当前存在事务,则加入该事务;如果不存在,则创建一个新的事务
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        // 设置事务隔离级别为READ_COMMITTED,表示一个事务可能看到另一个事务已提交的数据
        transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);

        // 设置事务超时时间为30秒,如果在30秒内事务没有完成,则自动回滚
        transactionTemplate.setTimeout(30);

        return transactionTemplate;
    }
}

常用方法

  • setPropagationBehavior(int propagationBehavior):设置事务的传播行为,例如TransactionDefinition.PROPAGATION_REQUIRED

  • setIsolationLevel(int isolationLevel):设置事务的隔离级别,例如TransactionDefinition.ISOLATION_DEFAULT

  • setTimeout(int timeout):设置事务的超时时间,单位为秒

  • executeWithoutResult(TransactionCallbackWithoutResult action):执行不需要返回结果的事务操作

    • java
      @Service
      public class MyService {
      
          // 自动注入TransactionTemplate
          @Autowired
          private TransactionTemplate transactionTemplate;
      
          // 服务层方法,使用TransactionTemplate执行事务
          public void performOperation() {
              // 使用注入的transactionTemplate执行事务操作
              transactionTemplate.executeWithoutResult(status -> {
                  try {
                      // 执行事务操作,例如保存对象到数据库
                      repository.save(someObject);
                  } catch (Exception e) {
                      // 出现异常时回滚事务
                      status.setRollbackOnly();
                      // 可以选择抛出异常或进行其他错误处理
                      throw e;
                  }
              });
          }
      }
  • execute(TransactionCallback<T> action):执行需要返回结果的事务操作

    • java
      @Service
      public class MyService {
      
          // 自动注入TransactionTemplate
          @Autowired
          private TransactionTemplate transactionTemplate;
      
          // 服务层方法,使用TransactionTemplate执行事务
          public Integer performUpdateOperation() {
              // 使用注入的transactionTemplate执行事务操作
              return transactionTemplate.execute(status -> {
                  try {
                      // 执行事务操作,例如更新数据库中的记录
                      int updatedCount = repository.update(someObject);
                      // 返回操作结果
                      return updatedCount;
                  } catch (Exception e) {
                      // 出现异常时回滚事务
                      status.setRollbackOnly();
                      // 可以选择抛出异常或进行其他错误处理
                      throw e;
                  }
              });
          }
      }