编程式事务,更加精细化的控制

在某些情况下,你会发现虽然使用了 @Transactional 注解 但是事务并没有回滚,后面的逻辑依旧继续执行了,为什么呢?

声明式事务注解为什么失效了

声明式事务失效的原因,主要由以下几点构成:

  • 方法可见性@Transactional 仅在 public 方法上生效
  • 自调用 :当类中的方法是通过调用同一个类当中的另外一个 @Transactional 方法的时候,事务可能不会生效。这是因为这个事务注解是通过 AOP 实现的,而 Spring 的 AOP 代理机制在这种情况下不会触发。
  • 异常处理 :只有 RuntimeExceptionError 类型的异常会触发事务回滚。如果抛出的是 checked exception,事务不会回滚,除非指定 rollback 属性
  • 代理对象 :确保是在 Spring 管理的代理对象上调用方法,如果直接使用 new 关键字实例化的对象(未被 Spring 管理),那么 Spring 的 AOP 代理机制不会触发

什么是编程式事务?有哪些优点?

编程事务(Programmatic Transaction)是一种通过代码显式地管理事务的方式,而不是依赖声明式事务(Declarative Transaction)中使用的注解或者 xml 配置,在编程式事务中,开发人员通过编写代码来开启、提交和回滚事务,以精细控制事务的边界和行为

编程式事务的优点:

  • 精细控制:编程事务允许开发者通过代码精细地控制事务的生命周期,包括开始、提交和回滚。可以更加具体业务需求,灵活地管理事务
  • 动态处理:在允许时可以根据业务逻辑的不同情况,动态决定事务的行为。特别适合需要在代码执行过程中,根据某些条件来开启、提交或者回滚事务的场景。
  • 适用于复杂事务:在一个方法中需要多次开启和关闭事务,或需要嵌套事务的复杂场景中,编程事务可以提供更大的灵活性和控制力
  • 灵活性高:能够在代码中实现复炸的事务逻辑,可以精确控制事务的边界和行为,这在需要多个步骤或调用之间共享事务上下文的时候非常有用
  • 性能提升:通过精细化控制事务的边界,减少不必要的事务开启和提交,从而减少事务开销;通过明确事务的开始和结束,可以确保事务范围尽可能的缩小,减少长时间占用数据库资源,提高系统的并发性,通过灵活的事务管理,可以在必要时才进行事务回滚,减少回滚操作带来的性能开销。

编程式事务的缺点:

  • 代码入侵性强(核心劣势) :事务逻辑与业务 紧密耦合 在一起,业务代码中会夹杂大量的事务控制代码(比如 try-catch 中执行回滚等),这样会导致代码臃肿,可读性变差,可维护性下降
  • 开发效率低,容易出错:开发者需要手动的编写事务的开启、提交和回滚,还要处理各种异常情况,增加了开发工作量,写得越多,越容易出错
  • 代码冗余:如果多个业务都需要进行事务控制,会出现大量重复代码,违反了 DRY (Don't Repeat Yourself)原则,后期修改需要改动多出的代码
  • 对开发人员要求高:开发人员需要熟悉事务的底层原理和相关 api 的使用,必须清除什么时候该提交,什么时候该回滚。

使用示例

下面是在 SpringBoot 使用编程式事务的两种方式,示例化代码如下

第一种

java 复制代码
@Service
public class MyService {

    @Resource
    private PlatformTransactionManager transactionManager;

    @Resource
    private MyMapper myMapper;

    public void myTransactionalMethod() {
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());

        try {
            // 业务逻辑代码
            myMapper.insertSomething(...);

            transactionManager.commit(status); // 提交事务
        } catch (Exception ex) {
            transactionManager.rollback(status); // 回滚事务
            throw ex; // 重新抛出异常
        }
    }
}

transactionManager.getTransaction(...): 会创建一个新的事务,并返回 TransactionStatus 对象,这个对象会是当前事务的状态,用它来进行事务的提交和回滚

上述代码的核心流程:开启事务→ 执行业务逻辑 → 无异常提交 / 有异常回滚

第二种

java 复制代码
@Service
public class MyService {

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private MyMapper myMapper;

    public void myTransactionalMethod() {
        transactionTemplate.execute(status -> {
            try {
                // 业务逻辑代码
                myMapper.insertSomething(...);

            } catch (Exception ex) {
                status.setRollbackOnly(); // 标记事务为回滚
                throw ex; // 重新抛出异常
            }
            return null;
        });
    }
}

TransactionTemplate 是一个简化了事务的工具类,代码编写者可以将代码重心放在业务代码上,可以更加方便的实现进行提交或者回滚,使得事务处理相关的代码更加简洁、冗余更少

总结

编程式事务是通过代码显式管理事务的方式,开发者需手动编写代码控制事务的开启、提交和回滚,而非依赖声明式事务中的注解或 XML 配置,以此实现对事务边界和行为的精细控制。

推荐使用 TransactionTemplate 进行编程式事务管理


本篇文章基于 小哈书 5.13 编写,欢迎大家访问小哈书

欢迎大家访问博主的个人博客网站 AZERL7的博客-a little world for you

相关推荐
一只努力的微服务2 小时前
【Calcite 系列】将 INTERSECT 转换为 EXISTS
java·calcite
是喵斯特ya2 小时前
数据库的权限提升
数据库·安全
玩转数据库管理工具FOR DBLENS2 小时前
企业数据架构选型指南:关系型与非关系型数据库的实战抉择
数据库·测试工具·mysql·oracle·架构·nosql
二进制_博客2 小时前
Doris2.x连载文章(2)
数据库·doris·mpp数据库
共享家95272 小时前
Redis背景知识
数据库·redis·缓存
盐焗西兰花2 小时前
鸿蒙学习实战之路-数据持久化键值型数据库KV-Store全攻略
数据库·学习·harmonyos
ホロHoro2 小时前
数据结构非线性部分(1)
java·数据结构·算法
Rinai_R2 小时前
Go 的调度模型
开发语言·后端·golang
t198751282 小时前
计算力学中经典四阶常微分方程的MATLAB求解方法
开发语言·matlab