Spring事物

发布于:2025-08-18 ⋅ 阅读:(14) ⋅ 点赞:(0)


大家好,今天想和大家分享一下Spring框架中的事务管理。这东西在实际开发中超级实用,尤其是处理数据库操作的时候,能帮我们避免很多坑。

为什么需要事务管理?

首先,事务就是一组操作,要么全成功,要么全失败。比如你转账,从A账户扣钱,再给B账户加钱,这两个步骤必须一起完成,要是扣钱成功了加钱失败,那不就乱套了?在Spring里,事务管理主要针对数据库操作,但也能扩展到其他资源。Spring提供了两种方式:编程式事务声明式事务。编程式就是手动写代码控制事务开始、提交、回滚;声明式更方便,通过注解或XML配置,让Spring自动帮你管。

Spring事务的核心概念

1. 事务传播行为

传播行为决定了事务在方法嵌套调用时的行为。Spring定义了7种:

传播行为 描述
REQUIRED 如果当前有事务,就加入;没有就新建一个。最常用。
REQUIRES_NEW 总是新建一个事务,挂起当前事务。
NESTED 嵌套事务,类似于REQUIRES_NEW,但回滚时只影响子事务。
SUPPORTS 有事务就加入,没有就非事务执行。
MANDATORY 必须有事务,否则抛异常。
NOT_SUPPORTED 非事务执行,如果有就挂起。
NEVER 必须非事务,否则抛异常。

2. 隔离级别

Spring支持数据库的隔离级别:

隔离级别 描述
DEFAULT 用数据库默认的。
READ_UNCOMMITTED 最低级别,可能脏读。
READ_COMMITTED 避免脏读,但可能不可重复读。
REPEATABLE_READ 避免不可重复读,但可能幻读。
SERIALIZABLE 最高级别,完全串行,但性能差。

实际项目中,READ_COMMITTED够用了,除非有特殊需求。

3. 回滚规则

默认情况下,Spring只在RuntimeException时回滚,Checked Exception不会。你可以用@Transactional(rollbackFor = Exception.class)指定回滚的异常类型。

如何配置Spring事务?

Spring Boot时代,配置超级简单。主要用注解方式。

使用@Transactional注解

在Service方法上加:

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
        User from = userRepository.findById(fromId).orElseThrow();
        User to = userRepository.findById(toId).orElseThrow();

        from.setBalance(from.getBalance().subtract(amount));
        to.setBalance(to.getBalance().add(amount));

        userRepository.save(from);
        userRepository.save(to);

        // 模拟异常
        int i = 10 / 0;
    }
}

这个例子中,如果抛异常,整个转账操作都会回滚。

事务失效的常见场景

1. 方法不是public的

Spring的事务是基于AOP代理实现的,默认只对public方法生效。如果你把@Transactional加在protected、private或package-private方法上,事务不会触发。

2. 同一个类内部方法调用

假如类A有方法foo()调用bar(),bar()有@Transactional,但因为没走代理(直接this.bar()),事务不生效。

解决方案

  • 在同一个类中不要用到内部方法调用
  • AopContext.currentProxy()走代理,但需@EnableAspectJAutoProxy(exposeProxy = true)。

3. 异常被捕获没抛出

@Transactional默认只在抛出RuntimeException时回滚。如果你try-catch了异常,没再抛,事务就提交了。

4. 数据库不支持事务

数据库不支持事务:如MyISAM引擎,用InnoDB。

总结

我在这篇文章中分享了Spring事务管理的实用经验,从为什么需要事务入手,解释了它如何确保操作的原子性,比如转账场景。接着,我详细介绍了核心概念,包括传播行为和隔离级别的表格展示,以及回滚规则。然后,我展示了如何用@Transactional注解配置事务,并举了转账代码例子。最后,我列出了事务失效的常见坑,如非public方法和类内调用问题,希望能帮大家在开发中避开雷区,更高效地处理数据库操作。


网站公告

今日签到

点亮在社区的每一天
去签到