Spring事务传播行为详解

Spring事务传播行为详解

引言

事务传播行为是Spring框架用于解决方法间事务调用问题的核心机制。当一个方法调用另一个方法时,如何处理事务的加入、创建、挂起等行为,直接影响数据一致性和系统性能。本文将深入解析Spring的7种事务传播行为、其底层实现原理以及在Spring Boot中的最佳实践。

一、七种传播行为

1.1 传播行为概览

Spring定义了7种事务传播行为:REQUIRED(默认):支持当前事务,如果不存在则创建新事务;REQUIRES_NEW:挂起当前事务,创建新事务;SUPPORTS:支持当前事务,如果不存在则以非事务执行;NOT_SUPPORTED:以非事务执行,挂起当前事务;MANDATORY:必须在事务中执行,否则抛异常;NEVER:必须在非事务中执行,否则抛异常;NESTED:如果当前存在事务,则在嵌套事务中执行。

1.2 行为详解

public enum Propagation {
    REQUIRED,       // 0 - 默认
    REQUIRES_NEW,   // 1 - 创建新事务
    SUPPORTS,       // 2 - 跟随当前事务
    NOT_SUPPORTED,  // 3 - 非事务执行
    MANDATORY,      // 4 - 强制事务
    NEVER,          // 5 - 强制非事务
    NESTED          // 6 - 嵌套事务
}

二、REQUIRED行为

2.1 基本原理

REQUIRED是默认的传播行为。如果当前存在事务,则加入该事务;如果不存在事务,则创建新事务。

@Service
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private UserService userService;
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void createOrder(Order order) {
        // 使用当前事务
        orderRepository.save(order);
        
        // 调用用户服务,也在同一事务中
        userService.updateUserBalance(order.getUserId(), 
            order.getAmount());
    }
}

@Service
public class UserService {
    
    @Transactional(propagation = Propagation.REQUIRED)  // 默认
    public void updateUserBalance(Long userId, BigDecimal amount) {
        // 与调用方在同一事务中
    }
}

2.2 事务合并

@Transactional(propagation = Propagation.REQUIRED)
public void outerMethod() {
    // 事务T1开始
    doSomethingA();
    
    innerMethod();  // 加入事务T1
    
    doSomethingB();
    
    // 提交事务T1
}

@Transactional(propagation = Propagation.REQUIRED)
public void innerMethod() {
    // 加入外层事务T1
    doSomethingC();
}

三、REQUIRES_NEW行为

3.1 基本原理

REQUIRES_NEW总是创建新事务,挂起当前事务(如果存在)。

@Service
public class OrderService {
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void createOrder(Order order) {
        orderRepository.save(order);
        
        // 创建独立新事务T2
        notificationService.sendNotification(order);
        
        // 即使T2失败,T1中的订单仍会提交
    }
}

@Service
public class NotificationService {
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void sendNotification(Order order) {
        // 在独立事务中执行
        // 失败不会影响调用方事务
    }
}

3.2 使用场景

REQUIRES_NEW适用于日志记录、审计追踪、发送通知等辅助功能,即使失败也不应影响主业务。

四、NESTED嵌套事务

4.1 基本原理

NESTED使用JDBC的保存点机制,在嵌套事务中执行。

@Service
public class OrderService {
    
    @Transactional(propagation = Propagation.REQUIRED)
    public void createOrder(Order order) {
        orderRepository.save(order);
        
        // 创建保存点
        nestedMethod();
        
        // 嵌套方法失败只会回滚到保存点
    }
    
    @Transactional(propagation = Propagation.NESTED)
    public void nestedMethod() {
        // 在嵌套事务中执行
    }
}

4.2 与REQUIRES_NEW的区别

// REQUIRED_NEW:完全独立的事务
// - 外层事务挂起
// - 内层事务独立提交/回滚
// - 内层回滚不影响外层

// NESTED:同一事务的嵌套
// - 不挂起外层事务
// - 使用保存点机制
// - 嵌套回滚只回滚到保存点

五、SUPPORTS行为

5.1 基本原理

SUPPORTS如果有事务则加入,否则以非事务执行。

@Service
public class CacheService {
    
    @Transactional(propagation = Propagation.SUPPORTS)
    public Object getData(String key) {
        // 如果在事务中,可以利用事务一致性
        // 不在事务中也可以正常工作
        Cache cache = cacheManager.getCache("data");
        return cache.get(key);
    }
}

六、NOT_SUPPORTED行为

6.1 基本原理

NOT_SUPPORTED挂起当前事务,以非事务方式执行。

@Service
public class ReportService {
    
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void generateReport(ReportRequest request) {
        // 长时间运行,不应在事务中
        // 挂起调用方的事务
    }
}

七、其他传播行为

7.1 MANDATORY

@Transactional(propagation = Propagation.MANDATORY)
public void executeInTransaction() {
    // 必须在有事务的情况下调用
    // 如果没有事务,抛出IllegalTransactionStateException
}

7.2 NEVER

@Transactional(propagation = Propagation.NEVER)
public void executeWithoutTransaction() {
    // 必须在没有事务的情况下调用
    // 如果有事务,抛出IllegalTransactionStateException
}

八、事务隔离级别

8.1 隔离级别定义

public enum Isolation {
    DEFAULT,           // 使用数据库默认
    READ_UNCOMMITTED,  // 读未提交
    READ_COMMITTED,    // 读已提交
    REPEATABLE_READ,   // 可重复读
    SERIALIZABLE       // 串行化
}

@Transactional(isolation = Isolation.READ_COMMITTED)
public void readData() {
    // 使用读已提交隔离级别
}

8.2 隔离级别问题

脏读:一个事务读取另一个事务未提交的数据;不可重复读:一个事务两次读取同一数据,结果不同;幻读:一个事务按条件查询,结果包含另一个事务插入的数据。

九、Spring Boot配置

9.1 全局事务配置

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5

  jpa:
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        connection:
          isolation: 2  # READ_COMMITTED

9.2 自定义事务管理器

@Configuration
public class TransactionConfig {
    
    @Bean
    public PlatformTransactionManager transactionManager(
            DataSource dataSource) {
        DataSourceTransactionManager manager = 
            new DataSourceTransactionManager(dataSource);
        manager.setDefaultTimeout(30);
        return manager;
    }
    
    @Bean
    public TransactionTemplate transactionTemplate(
            PlatformTransactionManager transactionManager) {
        TransactionTemplate template = new TransactionTemplate(
            transactionManager);
        template.setIsolationLevel(
            TransactionDefinition.ISOLATION_READ_COMMITTED);
        template.setPropagationBehavior(
            TransactionDefinition.PROPAGATION_REQUIRED);
        return template;
    }
}

十、最佳实践

10.1 传播行为选择

@Service
public class TransactionStrategy {
    
    // 核心业务逻辑 - REQUIRED
    @Transactional(propagation = Propagation.REQUIRED)
    public void coreBusiness() {
        // 需要事务保证一致性
    }
    
    // 日志记录 - REQUIRES_NEW
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logOperation() {
        // 独立事务,失败不影响主业务
    }
    
    // 只读操作 - SUPPORTS
    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public List<?> query() {
        // 可以利用事务优化,但不强制
    }
}

10.2 避免长事务

@Service
public class OptimizedService {
    
    @Transactional
    public void optimizedOrderProcess(Order order) {
        // 验证
        validateOrder(order);
        
        // 执行业务
        orderRepository.save(order);
        
        // 不要在事务中做这些耗时操作
        // 提交事务后,再发送通知
        sendNotificationAsync(order);
    }
}

总结

理解Spring事务传播行为对于构建正确的数据访问层至关重要。REQUIRED适合大多数场景;REQUIRES_NEW适合需要独立提交的操作;NESTED适合需要部分回滚的场景。合理选择传播行为和隔离级别,可以平衡数据一致性和系统性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值