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

 更新时间:2024年11月04日 09:25:44   作者:小乔努力变强  
Spring框架中,事务管理可以通过编程式事务和声明式事务两种方式实现,编程式事务通过手动编码控制事务的开始、提交和回滚,允许开发者精确控制事务,但增加了代码复杂度,声明式事务则通过@EnableTransactionManagement注解启用事务管理

spring中控制事务的方式有两种:编程式事务和声明式事务,今天我以两种事务出发,对spring中实现事务的@EnableTransactionManagement和@Transaction两个注解的底层原理进行讨论。

一、编程式事务

什么是编程式事务?

硬编码的方式实现事务,在代码中手动开始、提交和回滚事务

编程式事务实现思想是什么?

  • 配置PlatformTransactionManager事务管理器去控制事务
  • 配置TransactionDefinition设置事务属性
  • 配置TransactionTemplate控制事务

步骤和原理

1、定义数据源

2、定义一个PlatformTransactionManager 事务管理器,指定数据源。控制事务的操作(开始、提交、回滚)

3、定义TransactionDefinition 事务属性,可以配置事务属性信息

4、开启事务操作。通过调用getTransaction方法

补充:ThreadLocal中存储了datasource和connection的映射

这样当我们开启事务的时候会创建一个数据库连接,通过ThreadLocal保证线程的同步

5、执行业务操作

6、commit提交/rollback回滚事务

优缺点

优点:

  • 以在代码中精确地控制事务的起始点、提交点和回滚点
  • 实现更细粒度的事务管理

缺点:

  • 代码侵入性:编程式事务管理会将事务管理逻辑直接嵌入到业务代码中,增加了代码的复杂度和维护成本,使得业务逻辑与事务管理耦合在一起。
  • 重复性工作:在多个业务方法中可能需要重复编写事务管理逻辑,增加了代码冗余和维护工作量。

二、声明式事务

什么是声明式事务?

通过配置的方式去管理事务,可以是xml配置文件,也可以使用spring提供的@Transactional注解

声明式事务实现思想是什么?

  • 添加@EnableTransactionManagement注解
  • 添加@Transactional注解

步骤和原理

1、启用事务管理功能-配置类上加上@EnableTransactionManagement注解

2、定义事务管理器

3、需要开启事务的目标接口/类/方法上添加@Transaction注解

4、执行业务逻辑

5、启动spring容器,获取bean执行业务逻辑

优缺点

优点:

  • 与业务逻辑分离:声明式事务管理将事务管理逻辑从业务代码中分离出来,使得业务逻辑更清晰,降低了代码的耦合性。
  • 配置简单:通过注解或XML配置,可以简单地定义事务的传播行为、隔离级别等属性,而无需在每个业务方法中编写重复的事务管理代码。
  • 易于维护:由于事务管理逻辑集中在配置中,易于维护和修改,提高了代码的可读性和可维护性。
  • 提高一致性:声明式事务管理可以确保在所有业务方法中都应用相同的事务管理策略,提高了事务管理的一致性。

缺点:

  • 灵活性有限:声明式事务管理的灵活性相对较低,无法在运行时动态地改变事务管理策略,有一定的局限性。
  • RPC远程调用成功,但是本地事务回滚了,RPC调用无法回滚。并且事务中有远程调用,会拉长整个事务,导致本地事务的数据库连接一致被占用,最后可能会导致数据库连接池耗尽

在阿里巴巴的开发手册中也明确标出,我们用@Transactional注解的时候要谨慎,大家在业务场景中要谨慎使用哦!

上面我已经对spring实现事务的两种方式分别进行了说明,下面我们看看它的源码,解开事务这个神秘面纱!

三、源码分析

@EnableTransactionManagement

作用是什么?

开启spring自动管理事务。在spring容器启动的时候,会拦截所有bean的创建,判断当前bean中有没有用@Transaction注解,是不是需要让spring管理事务

判断规则:

  • public方法上有没有用@Transaction注解和bean的类相关的类/接口上有没有用@Transaction注解
  • 当满足规则之后会通过aop的方式创建代理,并且在代理中添加一个TransactionInterceptor拦截器

注意:@Transaction注解在代理对象被创建并且方法被调用时生效

@Transactional注解生效,必须确保Spring能够为目标类创建代理对象,并且方法通过代理对象调用

TransactionInterceptor拦截器的作用是什么?

拦截@Transaction方法,在方法前后添加事务额外逻辑

如果代理中还有其他拦截器,拦截器的顺序如何指定呢?

通过order()方法修改事务拦截器的执行顺序

注意:默认值是 LOWEST_PRECEDENCE = Integer.MAX_VALUE,拦截器的执行顺序是order升序

 int order() default Ordered.LOWEST_PRECEDENCE;

@Import(TransactionManagementConfigurationSelector.class)在这里的作用是什么?

@Import的作用是批量导入需要注册的类,完成bean的注册

那@Import导入了哪些类?

通过点进去TransactionManagementConfigurationSelector我们发现,里面有一个selectImports方法,这个方法的返回值是一个字符串数组,返回的字符串数组如果是正常的全限定类名才会被容器识别

通过查看selectImports方法源码,我们发现return了两个类-AutoProxyRegistrar、ProxyTransactionManageMentConfiguration,也就是说Import导入了这两个类

  • AutoProxyRegistrar:启用spring aop功能,创建代理
  • ProxyTransactionManageMentConfiguration:在aop中添加事务拦截器

①、AutoProxyRegistrar

点进源码,我们看registerBeanDefinitions这个方法,看过spring容器启动流程的小伙伴会发现,其中流程就会调用这个方法,AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)作用是向spring容器注册一个自动代理创建器,从而启用AOP代理的功能

在方法内部会导入InfrastructureAdvisorAutoProxyCreator类,给spring 容器中注册了一个后置处理器-BeanPostProcessor,拦截所有bean的创建并将符合规则的bean创建代理,对类进行增强

在生命周期阶段,创建bean的时候只有需要增强,就会调用BeanPostProcessor的after进行增强

②、ProxyTransactionManageMentConfiguration

配置类,一般是提供加了@Bean的一些方法。注册了一个事务拦截器TransactionInterceptor

总结

通过对上面两个导入的类的源码分析我们明确了他们的作用,我们使用@Transaction标注的bean会通过AutoProxyRegistrar去启用aop功能,通过ProxyTransactionManagementConfiguration在aop中添加事务拦截器从而实现事务管理

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Jmeter测试时遇到的各种乱码问题及解决

    Jmeter测试时遇到的各种乱码问题及解决

    这篇文章主要介绍了Jmeter测试时遇到的各种乱码问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • 详解Java实现数据结构之并查集

    详解Java实现数据结构之并查集

    并查集这种数据结构,可能出现的频率不是那么高,但是还会经常性的见到,其理解学习起来非常容易,通过本文,一定能够轻轻松松搞定并查集
    2021-06-06
  • 关于pom.xml中maven无法下载springcloud包问题

    关于pom.xml中maven无法下载springcloud包问题

    小编遇到这样一个问题spring-cloud-starter-feign,spring-cloud-starter-eureka 一直无法下载,maven仓库中包路径显示为unknown,怎么解决呢?下面小编给大家带来了pom.xml中maven无法下载springcloud包问题,需要的朋友可以参考下
    2022-08-08
  • java Socket编程实现I/O多路复用的示例

    java Socket编程实现I/O多路复用的示例

    本文主要介绍了java Socket编程实现I/O多路复用的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-09-09
  • Java自定义类加载器实现类隔离详解

    Java自定义类加载器实现类隔离详解

    由于每种组件的不同版本所依赖的jar包不同,我们可以借鉴tomcat的实现方式,通过自定义类加载器打破双亲委派机制来实现类隔离,从而达到操作多组件多版本的目的。本文就来和大家详细聊聊实现方法
    2023-03-03
  • SpringBoot项目使用内置的单机任务调度功能详解

    SpringBoot项目使用内置的单机任务调度功能详解

    这篇文章主要介绍了SpringBoot项目使用内置的单机任务调度功能详解,SpringBoot框架中提供了2个注解来让开发者快速配置来实现单机定时任务调度的功能,分别是@EnableScheduling和 @Scheduled,需要的朋友可以参考下
    2024-01-01
  • 关于java自定义线程池的原理与实现

    关于java自定义线程池的原理与实现

    本文介绍了如何自定义线程池和阻塞队列,包括阻塞队列的实现方法,线程池的构建以及拒绝策略的应用,详细阐述了线程池中任务的提交和执行流程,以及如何处理任务超出队列容量的情况
    2022-04-04
  • 关于@GetMapping和@GetMapping(value=““)的区别

    关于@GetMapping和@GetMapping(value=““)的区别

    这篇文章主要介绍了关于@GetMapping和@GetMapping(value=““)的区别说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • SpringBoot整合RocketMQ的方法详解

    SpringBoot整合RocketMQ的方法详解

    这篇文章主要为大家详细介绍了SpringBoot整合RocketMQ的方法,文中的示例代码讲解详细,对我们学习有一定帮助,感兴趣的小伙伴可以了解一下
    2022-08-08
  • Springboot初始化项目并完成登入注册的全过程

    Springboot初始化项目并完成登入注册的全过程

    工作之余,想要学习一下SpringBoot,通过网络大量教程最终成功运行SpringBoot项目,下面这篇文章主要给大家介绍了关于Springboot初始化项目并完成登入注册的相关资料,需要的朋友可以参考下
    2022-10-10

最新评论