女朋友不懂Spring事务原理,今天给她讲清楚了!

简介: 该文章讲述了如何解释Spring事务管理的基本原理,特别是针对女朋友在面试中遇到的问题。文章首先通过一个简单的例子引入了传统事务处理的方式,然后详细讨论了Spring事务管理的实现机制。

女朋友最近在找新工作,被面试官频繁问Spring事务原理,女朋友没有看过Spring源码,一直要我给她讲原理,看到女朋友十分低落的表情,我下定决心一定要给他讲清楚了。

image.png

传统事务的做法

我一开始问她知不知道假如没有Spring要怎么实现事务,她说知道,我就要他把传统事务的流程图画出来给我看下,下面就是她给出的流程图


graph TD

A[开始] -->|A 获取连接| B(Connection conn = DriverManager.getConnection)

B -->|B 开启事务| G(conn.getAutoCommit)

G -->|C 执行CRUD| H(conn.prepareStatement)

H --> I{CRUD是否成功?}

I --> |E 成功| J[提交事务]

I --> |F 失败| K[回滚事务]
AI 代码解读

传统事务存在哪些问题

果然计算机科班出身的女朋友,技术底子还是阔以的[你强],我再问她这种传统处理事务的方案有哪些局限或者短板呢? 她说,除了CRUD的业务代码,还需要写事务管理相关的代码,平时的工作量就加大了,这个确实如此,传统的事务做法对程序员的工作量大大提高,同时也补充了我的看法: 1、传统事务代码与业务代码耦合,强度入侵业务代码,可扩展性差 2、如果一个业务功能里同时存在多个事务切换的时候,代码编写的就会非常复杂

正是为了解决这些缺陷,Spring团队就打造了Spring事务组件,这个模块组件封装了传统事务功能的逻辑,业务开发者不用关心事务管理代码,只管专注于业务开发,多么美哉!

image.png

Spring事务组件做了哪些伟大的事?

1、Spring定义了事务操作规范,提供了顶层统一的编程模型抽象,不管是Java事务API,还是Hibernate,下面就是Spring定义的顶层接口,规范了对事务操作定义:

public interface PlatformTransactionManager {
   
   
    //获取事务
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
    //提交事务
    void commit(TransactionStatus var1) throws TransactionException;
    //回滚事务
    void rollback(TransactionStatus var1) throws TransactionException;
}
AI 代码解读

2、同时支持声明式事务和编程式事务 女朋友又开始问了,什么是编程式事务?什么是声明式事务呢? 编程式事务和传统事务类似,它是和业务代码耦合在一起的,只不过Spring团队对事务管理进行了封装,提供了工具类

org.springframework.transaction.support.TransactionTemplate
AI 代码解读

使用姿势如下面所示:

transactionTemplate.execute(() -> {
   
   
    //业务代码
    userService.addUser(user);
    scoreService.addScore(score);
});
AI 代码解读

那什么是声明式事务呢? 声明式事务就是通过注解的形式完成事务功能,如下面的代码可以等同于上面编程式事务,使我们的业务代码在事务中执行。

@Transactional
public void doTransaction() {
   
   
    userService.addUser(user);
    scoreService.addScore(score);
}
AI 代码解读

Spring事务实现原理剖析

女朋友开始感兴趣了,这些Spring是如何做到的呢?

image.png

首先说编程式事务,这个比较简单,扒开他的源码可知,他就是通过将业务代码以函数表达式传入一个工具方法,方法里在执行业务代码前后织入事务管理的逻辑,如下面代码:

public class TransactionTemplate {
   
   

public <T> T execute(TransactionCallback<T> action) throws TransactionException {
   
   
            //获取数据库连接
            TransactionStatus status = transactionManager.getTransaction(this);
            Object result;
            try {
   
   
                //执行crud
                result = action.doInTransaction(status);
            } catch (Error | RuntimeException var5) {
   
   
                //异常回滚
                this.rollbackOnException(status, var5);
                throw var5;
            } catch (Throwable var6) {
   
   
                //异常回滚
                this.rollbackOnException(status, var6);
                throw new UndeclaredThrowableException(var6, "TransactionCallback threw undeclared checked exception");
            }
            //执行crud成功,提交事务
            this.transactionManager.commit(status);
            return result;
        }
    }
}
AI 代码解读

看到这个实现,就非常清楚了,Spring将事务管理代码和函数式编程结合完成了编程式事务的组装。

下面我重点讲下声明式事务的实现逻辑。

image.png 虽然表面上看着Spring通过一个注解就完成了事务的功能,实际上底层有很多的逻辑,它需要能够拦截事务方法,并且在事务方法前后嵌入事务管理逻辑,完成事务开启,提交,回滚等逻辑,在Spring生态中,AOP技术就是一种在方法前后嵌入一些通用代码的手段,确实如此,Spring声明式事务就是借助Spring的AOP能力实现的。 TransactionInterceptor就是Spring内部定义的一个切面,她实现了MethodInterceptor接口就像我们平时定义一个切面统一打印日志一样,这个切面是Spring内置的一个切面,专门用来处理数据库事务的。 在ProxyTransactionManagementConfiguration配置类中,对事务切面进行了定义


//定义拦截器
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
   
   
   TransactionInterceptor interceptor = new TransactionInterceptor();
   interceptor.setTransactionAttributeSource(transactionAttributeSource());
   if (this.txManager != null) {
   
   
      interceptor.setTransactionManager(this.txManager);
   }
   return interceptor;
}
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
   
   
   BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
   advisor.setTransactionAttributeSource(transactionAttributeSource());
   advisor.setAdvice(transactionInterceptor());
   if (this.enableTx != null) {
   
   
      advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
   }
   return advisor;
}
AI 代码解读

这样Spring容器启动之后,就有一个全局的事务切面了。拦截到@Transaction注解的方法时,会触发下面方法执行

public class TransactionInterceptor{
   
   
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
   
   

        Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
                //在事务中执行目标方法
        return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
    }
}
AI 代码解读

invokeWithinTransaction方法就是Spring事务嵌入事务管理方法到业务方法前后的具体实现了。看里面的源码就非常熟悉了,这个和编程式事务工具类TransactionTemplate的实现如出一辙,女朋友终于恍然大悟,原来是这样。

public class TransactionInterceptor{
   
   

    protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
            final InvocationCallback invocation) throws Throwable {
   
   

        TransactionAttributeSource tas = getTransactionAttributeSource();
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

        //获取事务
        TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
        Object retVal = null;
        try {
   
   
            //执行目标方法crud
            retVal = invocation.proceedWithInvocation();
        }
        catch (Throwable ex) {
   
   
            // crud执行异常回滚事务
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        }
        finally {
   
   
            cleanupTransactionInfo(txInfo);
        }
        //提交事务
        commitTransactionAfterReturning(txInfo);
        return retVal;

    }
}
AI 代码解读

看到这里,其实Spring声明式事务的实现思路非常清晰了,无非就是借助Spring的AOP能力,内置了一个切面,并且在事务方法前后织入了事务管理的操作。 女朋友非常高兴,今天我的晚餐又可以加鸡腿了

image.png

彩蛋

能够看到这里的朋友真的是非常感激,我相信技术的力量是无穷的。 最后给大家一个安利,Spring事务虽然封装好了,一个注解就可以完成事务的功能,但是有没有一种可能?你的功能需要感知你的业务代码的事务是成功还是失败了?Spring团队想到了这种可能,提供了一个口子给我们,这个就是事务同步器!!!,事务同步器是异步的,他会在事务提交前后通知到你,只要继承下面的抽象类即可。

public abstract class TransactionSynchronizationAdapter implements TransactionSynchronization, Ordered {
   
   

   @Override
   public int getOrder() {
   
   
      return Ordered.LOWEST_PRECEDENCE;
   }

   @Override
   public void suspend() {
   
   
   }

   @Override
   public void resume() {
   
   
   }

   @Override
   public void flush() {
   
   
   }

   @Override
   public void beforeCommit(boolean readOnly) {
   
   
   }

   @Override
   public void beforeCompletion() {
   
   
   }

   @Override
   public void afterCommit() {
   
   
   //这里可以感知事务提交完成
   }

   @Override
   public void afterCompletion(int status) {
   
   
   //这里感知事务完成
   }

}
AI 代码解读

哈哈哈,这个实现有没有很优雅,每次看Spring的组件都会在心里给Spring团队的大神点赞,封装好组件给我们用,同时提供扩展点给我们,真的非常给力。

目录
打赏
0
4
4
0
42
分享
相关文章
Spring中事务失效的场景
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效 , 如果使用的是被代理对象调用, 那么@Transactional会失效 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效 如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常, @Transactional也会失效
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——常见问题总结
本文总结了Spring Boot中使用事务的常见问题,虽然通过`@Transactional`注解可以轻松实现事务管理,但在实际项目中仍有许多潜在坑点。文章详细分析了三个典型问题:1) 异常未被捕获导致事务未回滚,需明确指定`rollbackFor`属性;2) 异常被try-catch“吃掉”,应避免在事务方法中直接处理异常;3) 事务范围与锁范围不一致引发并发问题,建议调整锁策略以覆盖事务范围。这些问题看似简单,但一旦发生,排查难度较大,因此开发时需格外留意。最后,文章提供了课程源代码下载地址,供读者实践参考。
79 0
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——Spring Boot 事务配置
本文介绍了 Spring Boot 中的事务配置与使用方法。首先需要导入 MySQL 依赖,Spring Boot 会自动注入 `DataSourceTransactionManager`,无需额外配置即可通过 `@Transactional` 注解实现事务管理。接着通过创建一个用户插入功能的示例,展示了如何在 Service 层手动抛出异常以测试事务回滚机制。测试结果表明,数据库中未新增记录,证明事务已成功回滚。此过程简单高效,适合日常开发需求。
189 0
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——事务相关
本文介绍Spring Boot事务配置管理,阐述事务在企业应用开发中的重要性。事务确保数据操作可靠,任一异常均可回滚至初始状态,如转账、购票等场景需全流程执行成功才算完成。同时,事务管理在Spring Boot的service层广泛应用,但根据实际需求也可能存在无需事务的情况,例如独立数据插入操作。
50 0
RAG 调优指南:Spring AI Alibaba 模块化 RAG 原理与使用
通过遵循以上最佳实践,可以构建一个高效、可靠的 RAG 系统,为用户提供准确和专业的回答。这些实践涵盖了从文档处理到系统配置的各个方面,能够帮助开发者构建更好的 RAG 应用。
1408 115
Spring核心原理剖析与解说
每个部分都是将一种巨大并且复杂的技术理念传达为更易于使用的接口,而这就是Spring的价值所在,它能让你专注于开发你的应用,而不必从头开始设计每一部分。
124 32
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
112 10
【Spring】【事务】初学者直呼学会了的Spring事务入门
本文深入解析了Spring事务的核心概念与使用方法。Spring事务是一种数据库事务管理机制,通过确保操作的原子性、一致性、隔离性和持久性(ACID),维护数据完整性。文章详细讲解了声明式事务(@Transactional注解)和编程式事务(TransactionTemplate、PlatformTransactionManager)的区别与用法,并探讨了事务传播行为(如REQUIRED、REQUIRES_NEW等)及隔离级别(如READ_COMMITTED、REPEATABLE_READ)。
106 1
Spring框架 - 深度揭秘Spring框架的基础架构与工作原理
所以,当你进入这个Spring的世界,看似一片混乱,但细看之下,你会发现这里有个牢固的结构支撑,一切皆有可能。不论你要建设的是一座宏大的城堡,还是个小巧的花园,只要你的工具箱里有Spring,你就能轻松搞定。
101 9
Spring中的事务是如何实现的
1. Spring事务底层是基于数据库事务和AOP机制的 2. ⾸先对于使⽤了@Transactional注解的Bean,Spring会创建⼀个代理对象作为Bean 3. 当调⽤代理对象的⽅法时,会先判断该⽅法上是否加了@Transactional注解 4. 如果加了,那么则利⽤事务管理器创建⼀个数据库连接 5. 并且修改数据库连接的autocommit属性为false,禁⽌此连接的⾃动提交,这是实现Spring事务⾮ 常重要的⼀步 6. 然后执⾏当前⽅法,⽅法中会执⾏sql 7. 执⾏完当前⽅法后,如果没有出现异常就直接提交事务 8. 如果出现了异常,并且这个异常是需要回滚的就会回滚事务
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问