Spring Boot 事务管理完整教程

一、注解事务(声明式事务)

1. 基础配置

java 复制代码
// 启动类添加注解
@SpringBootApplication
@EnableTransactionManagement  // 通常默认开启,可省略
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2. 使用 @Transactional

java 复制代码
@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    // 基本用法
    @Transactional
    public void createUser(User user) {
        userMapper.insert(user);
        // 发生异常自动回滚
    }
    
    // 指定回滚异常
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(User user) throws Exception {
        userMapper.update(user);
        if (user.getAge() < 0) {
            throw new Exception("年龄不能为负数");
        }
    }
    
    // 不回滚指定异常
    @Transactional(noRollbackFor = NullPointerException.class)
    public void deleteUser(Long id) {
        userMapper.delete(id);
        if (id == null) {
            throw new NullPointerException(); // 不会回滚
        }
    }
    
    // 设置事务传播行为
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void saveLog(Log log) {
        // 新开事务,不受外层影响
        logMapper.insert(log);
    }
    
    // 设置超时和只读
    @Transactional(timeout = 30, readOnly = true)
    public List<User> findAllUsers() {
        return userMapper.selectAll();
    }
    
    // 隔离级别
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public User getUserById(Long id) {
        return userMapper.selectById(id);
    }
}

3. 常见传播行为

传播行为 说明
REQUIRED 默认,有事务则加入,无则新建
REQUIRES_NEW 挂起当前事务,新建事务
SUPPORTS 有事务则加入,无则非事务执行
NOT_SUPPORTED 非事务执行,挂起当前事务
MANDATORY 必须有事务,否则抛异常
NEVER 必须非事务,有事务则抛异常
NESTED 嵌套事务(Savepoint机制)

4. 注意事项

java 复制代码
// ❌ 错误:内部调用不生效
@Service
public class ServiceA {
    @Transactional
    public void methodA() {
        methodB();  // @Transactional 不生效!
    }
    
    @Transactional
    public void methodB() {}
}

// ✅ 正确:通过代理调用
@Service
public class ServiceA {
    @Autowired
    private ServiceA self;  // 注入自身代理
    
    @Transactional
    public void methodA() {
        self.methodB();  // 生效
    }
    
    @Transactional
    public void methodB() {}
}

二、手动事务(编程式事务)

方式1:TransactionTemplate(推荐)

java 复制代码
@Service
public class OrderService {
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    @Autowired
    private OrderMapper orderMapper;
    
    public void createOrder(Order order) {
        transactionTemplate.execute(status -> {
            try {
                orderMapper.insert(order);
                orderMapper.updateStock(order.getProductId());
                return order.getId();
            } catch (Exception e) {
                status.setRollbackOnly();  // 标记回滚
                throw new RuntimeException("创建订单失败", e);
            }
        });
    }
    
    // 配置事务属性
    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager manager) {
        TransactionTemplate template = new TransactionTemplate(manager);
        template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        template.setTimeout(30);
        return template;
    }
    
    // 复杂业务处理
    public Result processOrder(Order order) {
        return transactionTemplate.execute(status -> {
            try {
                // 业务逻辑1
                orderMapper.insert(order);
                
                // 条件判断手动回滚
                if (order.getAmount() < 0) {
                    status.setRollbackOnly();
                    return Result.fail("金额无效");
                }
                
                // 业务逻辑2
                paymentService.pay(order);
                
                return Result.success();
            } catch (Exception e) {
                status.setRollbackOnly();
                return Result.fail(e.getMessage());
            }
        });
    }
}

方式2:PlatformTransactionManager

java 复制代码
@Service
public class PaymentService {
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    @Autowired
    private AccountMapper accountMapper;
    
    public void transfer(Long fromId, Long toId, BigDecimal amount) {
        // 1. 定义事务属性
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
        
        // 2. 获取事务状态
        TransactionStatus status = transactionManager.getTransaction(def);
        
        try {
            // 扣款
            accountMapper.decreaseBalance(fromId, amount);
            // 加款
            accountMapper.increaseBalance(toId, amount);
            
            // 提交
            transactionManager.commit(status);
        } catch (Exception e) {
            // 回滚
            transactionManager.rollback(status);
            throw new RuntimeException("转账失败", e);
        }
    }
    
    // 嵌套事务示例
    public void complexBusiness() {
        // 外层事务
        DefaultTransactionDefinition outerDef = new DefaultTransactionDefinition();
        TransactionStatus outerStatus = transactionManager.getTransaction(outerDef);
        
        try {
            // 业务A
            doBusinessA();
            
            // 内层独立事务
            DefaultTransactionDefinition innerDef = new DefaultTransactionDefinition();
            innerDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus innerStatus = transactionManager.getTransaction(innerDef);
            try {
                doBusinessB();
                transactionManager.commit(innerStatus);
            } catch (Exception e) {
                transactionManager.rollback(innerStatus);
                // 内层失败不影响外层
            }
            
            transactionManager.commit(outerStatus);
        } catch (Exception e) {
            transactionManager.rollback(outerStatus);
            throw new RuntimeException("业务失败", e);
        }
    }
}

三、完整示例:用户注册+发送通知

java 复制代码
@Service
public class RegisterService {
    
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private NotificationService notificationService;
    
    // 组合使用
    public void register(User user) {
        // 主事务:用户注册
        Long userId = transactionTemplate.execute(status -> {
            try {
                // 保存用户
                userMapper.insert(user);
                
                // 初始化账户
                accountService.initAccount(user.getId());
                
                return user.getId();
            } catch (DuplicateKeyException e) {
                status.setRollbackOnly();
                throw new BusinessException("用户名已存在");
            }
        });
        
        // 非事务:发送通知(失败不影响注册)
        try {
            notificationService.sendWelcomeEmail(user.getEmail());
        } catch (Exception e) {
            log.error("发送邮件失败", e);
        }
    }
    
    // 混合使用
    @Transactional
    public void registerWithCoupon(User user, Coupon coupon) {
        // 声明式事务
        userMapper.insert(user);
        
        // 手动事务:发放优惠券(独立事务)
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        transactionTemplate.execute(status -> {
            try {
                couponService.giveCoupon(user.getId(), coupon);
                return true;
            } catch (Exception e) {
                log.error("发放优惠券失败", e);
                status.setRollbackOnly();
                return false;
            }
        });
        
        // 注册失败不影响优惠券发放
        if (user.getAge() < 0) {
            throw new IllegalArgumentException("年龄无效");
        }
    }
}

四、配置详解

bash 复制代码
# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: 123456
    
  # 事务配置
  transaction:
    default-timeout: 30  # 默认超时时间
    rollback-on-commit-failure: true  # 提交失败回滚
java 复制代码
@Configuration
public class TransactionConfig {
    
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    
    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager manager) {
        return new TransactionTemplate(manager);
    }
    
    // 配置多数据源事务
    @Bean
    public PlatformTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }
    
    @Bean
    public PlatformTransactionManager slaveTransactionManager(@Qualifier("slaveDataSource") DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }
}

五、选择建议

场景 推荐方式
简单CRUD @Transactional
复杂业务逻辑 TransactionTemplate
需要细粒度控制 PlatformTransactionManager
多数据源 手动指定事务管理器
测试环境 @Transactional + @Rollback

六、常见问题

java 复制代码
// 1. 事务不生效:方法必须是public
@Transactional  // private 不生效
private void method() {}

// 2. 异常被捕获不抛出不回滚
@Transactional
public void method() {
    try {
        // 业务
    } catch (Exception e) {
        // 不抛出 -> 不回滚,需要手动回滚
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

// 3. 默认只回滚RuntimeException,需要指定
@Transactional(rollbackFor = Exception.class)

以上涵盖了Spring Boot中事务的主要使用方式,建议优先使用@Transactional,需要更灵活控制时使用TransactionTemplate

相关推荐
城管不管2 小时前
前后端远程协作
java
青云计划2 小时前
Feed流
java·后端·spring
java1234_小锋2 小时前
String、StringBuilder、StringBuffer的区别?
java·开发语言
星原望野2 小时前
JAVA集合:List、Set和Map
java·开发语言·list·set·map·集合
2601_957787582 小时前
星链引擎矩阵系统:插件化多平台 API 网关与账号级隔离技术实践
java·矩阵·插件化架构
多敲代码防脱发3 小时前
Spring进阶(容器实现)
java·开发语言·后端·spring
m0_702036533 小时前
mysql如何通过索引减少行锁范围_mysql索引与加锁逻辑
jvm·数据库·python
qxwlcsdn3 小时前
如何用 IndexedDB 存储从 API 获取的超大列表并实现二级索引
jvm·数据库·python
星辰_mya3 小时前
彩云之上——[特殊字符]的架构师
java·后端·微服务·面试·架构