Spring的声明式事务和编程式事务

在 Spring 框架中,事务管理主要有两种方式:声明式事务编程式事务。两者各有优势,适用于不同的业务场景。


一、声明式事务

1. 实现机制

声明式事务基于 AOP(面向切面编程),通过代理机制(如 JDK 动态代理或 CGLIB)在方法执行前后插入事务管理逻辑。开发者只需通过注解或 XML 配置声明事务规则,Spring 会自动处理事务的开启、提交和回滚。

2. 常见注解

  • @Transactional:最常用的注解,用于类或方法上,声明事务边界。
  • 可配置属性:
    • propagation:事务传播行为(如 REQUIRED、REQUIRES_NEW 等)
    • isolation:事务隔离级别
    • timeout:事务超时时间
    • readOnly:是否只读事务
    • rollbackFor / noRollbackFor:指定哪些异常触发回滚

3. 优点

  • 解耦业务逻辑与事务管理:业务代码中无需嵌入事务控制逻辑。
  • 易于维护和扩展:通过配置即可修改事务行为。
  • 支持事务传播行为:适合复杂业务逻辑中的事务嵌套、传播等场景。
  • 符合开闭原则:新增业务逻辑不影响事务配置。

4. 缺点

  • 灵活性较低:无法在方法内部动态控制事务边界。
  • 自调用问题:若一个类内部调用另一个加了 @Transactional 的方法,事务可能不生效(因为代理失效)。
  • 异常处理需谨慎:默认只对 RuntimeExceptionError 回滚,需手动配置 rollbackFor 来处理 checked exception。

5. 使用场景

  • 常规 CRUD 操作:如增删改查,事务边界清晰。
  • 多层调用链:如 Service 层调用多个 DAO 方法,需要统一事务管理。
  • 需要事务传播行为的场景:如一个事务方法调用另一个事务方法,需控制传播方式。

二、编程式事务

1. 实现机制

编程式事务通过手动编写事务控制代码来管理事务,通常使用 TransactionTemplate 或直接使用 PlatformTransactionManager。开发者需要显式调用事务的开始、提交和回滚操作。

2. 常见方式

  • 使用 TransactionTemplate
transactionTemplate.execute(status -> {
    // 业务逻辑
    return null;
});
  • 使用 PlatformTransactionManager
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
    // 业务逻辑
    transactionManager.commit(status);
} catch (Exception e) {
    transactionManager.rollback(status);
}

3. 优点

  • 事务控制更灵活:可在代码中动态决定事务边界。
  • 适合复杂事务逻辑:如根据条件决定是否提交或回滚。
  • 避免自调用问题:因为事务控制是显式的,不受代理限制。

4. 缺点

  • 代码侵入性强:业务代码中混杂事务控制逻辑。
  • 可维护性差:事务逻辑与业务逻辑耦合,不易扩展。
  • 容易出错:手动控制事务边界容易遗漏提交或回滚。

5. 使用场景

  • 需要动态控制事务边界:如根据条件决定是否提交。
  • 跨多个方法调用:如多个方法调用之间需要共享同一个事务上下文。
  • 需要事务回调或事务监听:如事务提交后执行某些操作。
  • 在非 Spring 管理的类中使用事务:如工具类或非 Spring Bean。

三、总结

特性声明式事务编程式事务
实现方式AOP + 注解/配置手动编写事务控制代码
灵活性较低
可维护性
代码侵入性
异常处理默认只回滚 RuntimeException可自定义回滚策略
事务边界控制固定(方法级)动态(可精确控制)
适用场景常规业务逻辑复杂事务逻辑、动态控制

四、示例代码

1. 声明式事务

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void registerUser(User user) throws Exception {
        userRepository.save(user);
        // 模拟异常
        if (user.getName().equals("error")) {
            throw new Exception("注册失败");
        }
    }
}

2. 编程式事务(使用 TransactionTemplate)

@Service
public class UserService {

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private UserRepository userRepository;

    public void registerUser(User user) {
        transactionTemplate.execute(status -> {
            try {
                userRepository.save(user);
                if (user.getName().equals("error")) {
                    status.setRollbackOnly();
                    throw new RuntimeException("注册失败");
                }
                return null;
            } catch (Exception e) {
                status.setRollbackOnly();
                throw e;
            }
        });
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值