Spring Boot 声明式事务

目录

  • [1. 声明式事务概述](#1. 声明式事务概述)
  • [2. @Transactional注解详解](#2. @Transactional注解详解)
  • [3. 事务失效场景](#3. 事务失效场景)
  • [4. 事务使用最佳实践](#4. 事务使用最佳实践)
  • [5. 实战示例](#5. 实战示例)

1. 声明式事务概述

1.1 什么是声明式事务

声明式事务是Spring通过AOP(面向切面编程)实现的事务管理功能。通过@Transactional注解,可以将事务管理代码与业务代码分离,降低代码耦合度。

1.2 基础配置

java 复制代码
@Configuration
@EnableTransactionManagement  // 启用事务管理
public class TransactionConfig {
    // 事务管理器配置已经由Spring Boot自动完成
}

2. @Transactional注解详解

2.1 注解属性说明

java 复制代码
@Service
public class TransactionAttributesDemo {
    
    @Transactional(
        // 1. 事务传播行为
        propagation = Propagation.REQUIRED,  // 默认值
        
        // 2. 事务隔离级别
        isolation = Isolation.READ_COMMITTED,
        
        // 3. 事务超时时间(秒)
        timeout = 30,
        
        // 4. 是否只读事务
        readOnly = false,
        
        // 5. 回滚规则
        rollbackFor = {BusinessException.class},  // 导致回滚的异常类
        noRollbackFor = {ValidationException.class},  // 不回滚的异常类
        
        // 6. 事务管理器
        transactionManager = "transactionManager"
    )
    public void businessMethod() {
        // 业务逻辑
    }
}

2.2 事务传播行为详解

java 复制代码
@Service
@Slf4j
public class TransactionPropagationDemo {
    
    @Autowired
    private UserService userService;
    
    // 1. REQUIRED(默认):支持当前事务,如果不存在则创建新事务
    @Transactional(propagation = Propagation.REQUIRED)
    public void required() {
        // 业务逻辑
    }
    
    // 2. REQUIRES_NEW:创建新事务,挂起当前事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void requiresNew() {
        // 业务逻辑
    }
    
    // 3. NESTED:如果当前存在事务,则创建嵌套事务
    @Transactional(propagation = Propagation.NESTED)
    public void nested() {
        // 业务逻辑
    }
    
    // 4. SUPPORTS:支持当前事务,如果不存在则以非事务方式执行
    @Transactional(propagation = Propagation.SUPPORTS)
    public void supports() {
        // 业务逻辑
    }
    
    // 5. NOT_SUPPORTED:以非事务方式执行,如果存在事务则挂起
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void notSupported() {
        // 业务逻辑
    }
    
    // 6. MANDATORY:必须在事务中运行,如果不存在事务则抛出异常
    @Transactional(propagation = Propagation.MANDATORY)
    public void mandatory() {
        // 业务逻辑
    }
    
    // 7. NEVER:以非事务方式执行,如果存在事务则抛出异常
    @Transactional(propagation = Propagation.NEVER)
    public void never() {
        // 业务逻辑
    }
}

2.3 事务隔离级别详解

java 复制代码
@Service
public class TransactionIsolationDemo {
    
    // 1. READ_UNCOMMITTED:读未提交
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void readUncommitted() {
        // 可能读取到其他事务未提交的数据(脏读)
    }
    
    // 2. READ_COMMITTED:读已提交
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void readCommitted() {
        // 只能读取已经提交的数据,但可能出现不可重复读
    }
    
    // 3. REPEATABLE_READ:可重复读
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public void repeatableRead() {
        // 同一事务内多次读取结果一致,但可能出现幻读
    }
    
    // 4. SERIALIZABLE:串行化
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void serializable() {
        // 完全串行化执行,性能最差但是最安全
    }
}

3. 事务失效场景

3.1 常见事务失效情况

java 复制代码
@Service
public class TransactionInvalidDemo {
    
    // 1. 非public方法
    @Transactional
    private void privateMethod() {  // 事务无效
        // 业务逻辑
    }
    
    // 2. 同类内部调用
    public void outerMethod() {
        innerMethod();  // 事务无效
    }
    
    @Transactional
    public void innerMethod() {
        // 业务逻辑
    }
    
    // 3. 异常被捕获但未抛出
    @Transactional
    public void catchException() {
        try {
            // 业务逻辑
            throw new RuntimeException();
        } catch (Exception e) {
            log.error("异常", e);
            // 异常被吃掉,事务无法回滚
        }
    }
    
    // 4. 数据库引擎不支持事务(如MySQL的MyISAM)
    @Transactional
    public void mysqlEngine() {
        // 使用不支持事务的表引擎,事务无效
    }
    
    // 5. 异常类型不匹配
    @Transactional  // 默认只回滚RuntimeException
    public void exceptionType() throws Exception {
        throw new Exception("检查异常不会回滚");
    }
    
    // 6. 事务传播行为设置错误
    @Transactional(propagation = Propagation.NEVER)
    public void wrongPropagation() {
        // 在已有事务的情况下调用,将抛出异常
    }
    
    // 7. 未被Spring管理
    class NonSpringBean {
        @Transactional
        public void method() {  // 事务无效,因为不是Spring Bean
        }
    }
    
    // 8. 方法final修饰
    @Transactional
    public final void finalMethod() {  // 事务无效,因为final方法无法被代理
        // 业务逻辑
    }
}

4. 事务使用最佳实践

4.1 合理设置事务边界

java 复制代码
@Service
@Slf4j
public class TransactionBoundaryDemo {
    
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private OrderRepository orderRepository;
    
    // 错误示例:事务边界太大
    @Transactional
    public void wrongBoundary() {
        // 非事务操作:查询统计
        long count = userRepository.count();
        log.info("用户总数: {}", count);
        
        // 事务操作:创建订单
        createOrder();
        
        // 非事务操作:发送通知
        sendNotification();
    }
    
    // 正确示例:精确的事务边界
    public void rightBoundary() {
        // 非事务操作
        long count = userRepository.count();
        log.info("用户总数: {}", count);
        
        // 事务操作
        createOrderWithTransaction();
        
        // 非事务操作
        sendNotification();
    }
    
    @Transactional
    public void createOrderWithTransaction() {
        // 只包含需要事务的操作
        createOrder();
    }
}

4.2 正确处理事务异常

java 复制代码
@Service
@Slf4j
public class TransactionExceptionDemo {
    
    // 1. 定义自定义业务异常
    public class BusinessException extends RuntimeException {
        public BusinessException(String message) {
            super(message);
        }
    }
    
    // 2. 使用明确的回滚规则
    @Transactional(rollbackFor = Exception.class)
    public void handleBusinessException() {
        try {
            // 业务逻辑
            riskyOperation();
        } catch (BusinessException e) {
            // 记录业务异常
            log.error("业务异常", e);
            throw e;  // 重新抛出确保回滚
        } catch (Exception e) {
            // 记录系统异常
            log.error("系统异常", e);
            throw new RuntimeException("系统错误", e);
        }
    }
    
    // 3. 处理特定异常不回滚
    @Transactional(noRollbackFor = {ValidationException.class})
    public void handleValidationException() {
        try {
            // 业务逻辑
            validate();
        } catch (ValidationException e) {
            // 验证异常,记录但不回滚
            log.warn("验证失败", e);
        }
    }
}

5. 实战示例

5.1 转账业务实现

java 复制代码
@Service
@Slf4j
public class TransferService {
    
    @Autowired
    private AccountRepository accountRepository;
    
    @Transactional(rollbackFor = Exception.class)
    public void transfer(String fromAccount, String toAccount, BigDecimal amount) {
        // 1. 参数校验
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("转账金额必须大于0");
        }
        
        // 2. 查询账户
        Account from = accountRepository.findByAccountNo(fromAccount)
            .orElseThrow(() -> new BusinessException("转出账户不存在"));
        Account to = accountRepository.findByAccountNo(toAccount)
            .orElseThrow(() -> new BusinessException("转入账户不存在"));
        
        // 3. 余额检查
        if (from.getBalance().compareTo(amount) < 0) {
            throw new BusinessException("余额不足");
        }
        
        try {
            // 4. 执行转账
            from.setBalance(from.getBalance().subtract(amount));
            to.setBalance(to.getBalance().add(amount));
            
            // 5. 保存更改
            accountRepository.save(from);
            accountRepository.save(to);
            
            // 6. 记录交易日志
            logTransaction(from, to, amount);
            
        } catch (Exception e) {
            log.error("转账失败", e);
            throw new BusinessException("转账操作失败");
        }
    }
    
    private void logTransaction(Account from, Account to, BigDecimal amount) {
        // 记录交易日志的逻辑
    }
}

5.2 订单处理实现

java 复制代码
@Service
@Slf4j
public class OrderService {
    
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private InventoryService inventoryService;
    
    @Transactional(rollbackFor = Exception.class)
    public Order createOrder(OrderRequest request) {
        // 1. 创建订单
        Order order = new Order();
        order.setUserId(request.getUserId());
        order.setAmount(calculateAmount(request));
        order.setStatus(OrderStatus.CREATED);
        
        // 2. 保存订单
        order = orderRepository.save(order);
        
        try {
            // 3. 扣减库存(使用REQUIRES_NEW确保独立事务)
            inventoryService.deductInventory(request.getItems());
            
            // 4. 处理支付(使用REQUIRES_NEW确保独立事务)
            paymentService.processPayment(order);
            
            // 5. 更新订单状态
            order.setStatus(OrderStatus.PAID);
            order = orderRepository.save(order);
            
            return order;
        } catch (Exception e) {
            // 6. 异常处理
            order.setStatus(OrderStatus.FAILED);
            orderRepository.save(order);
            throw new BusinessException("订单处理失败", e);
        }
    }
    
    private BigDecimal calculateAmount(OrderRequest request) {
        // 计算订单金额的逻辑
        return BigDecimal.ZERO;
    }
}

关键点:

  1. 正确使用@Transactional注解及其属性
  2. 理解并避免事务失效的场景
  3. 合理设置事务边界和传播行为
  4. 正确处理事务中的异常
  5. 遵循事务使用的最佳实践

在实际开发中,声明式事务能满足大多数场景的需求,它提供了一种优雅的方式来管理事务,使开发者可以专注于业务逻辑的实现。

相关推荐
鼠鼠我捏,要死了捏2 小时前
深入解析Java NIO多路复用原理与性能优化实践指南
java·性能优化·nio
ningqw2 小时前
SpringBoot 常用跨域处理方案
java·后端·springboot
你的人类朋友2 小时前
vi编辑器命令常用操作整理(持续更新)
后端
superlls2 小时前
(Redis)主从哨兵模式与集群模式
java·开发语言·redis
胡gh2 小时前
简单又复杂,难道只能说一个有箭头一个没箭头?这种问题该怎么回答?
javascript·后端·面试
一只叫煤球的猫3 小时前
看到同事设计的表结构我人麻了!聊聊怎么更好去设计数据库表
后端·mysql·面试
uzong3 小时前
技术人如何对客做好沟通(上篇)
后端
叫我阿柒啊4 小时前
Java全栈工程师面试实战:从基础到微服务的深度解析
java·redis·微服务·node.js·vue3·全栈开发·电商平台
颜如玉4 小时前
Redis scan高位进位加法机制浅析
redis·后端·开源
Moment4 小时前
毕业一年了,分享一下我的四个开源项目!😊😊😊
前端·后端·开源