当前位置:首页 > 科技  > 软件

事务中存在多线程,怎么处理?

来源: 责编: 时间:2024-06-12 17:29:02 213观看
导读在 Spring 框架中,@Transactional 注解作为一种声明式事务管理的关键机制,其背后的工作原理远比简单的 AOP(面向切面编程)和 ThreadLocal 存储更为细腻。该注解的实现核心在于 Spring 的 TransactionInterceptor(事务拦截

在 Spring 框架中,@Transactional 注解作为一种声明式事务管理的关键机制,其背后的工作原理远比简单的 AOP(面向切面编程)和 ThreadLocal 存储更为细腻。该注解的实现核心在于 Spring 的 TransactionInterceptor(事务拦截器)以及它如何与 Spring 的代理机制、TransactionManager(事务管理器)协同工作,来确保事务的开启、提交或回滚等操作得以正确执行。NJL28资讯网——每日最新资讯28at.com

一 注解解析与代理生成

当 Spring 容器初始化时,会通过 AnnotationTransactionAttributeSource 扫描并识别出所有标有 @Transactional 的方法。这些方法在被调用前,Spring 会根据配置(如基于接口或类的代理)为它们创建动态代理对象。如果是基于接口的代理,则使用 JDK Dynamic Proxy;如果是基于类的,则采用 CGLIB。这个代理对象会在目标方法调用前后插入事务处理逻辑。NJL28资讯网——每日最新资讯28at.com

1.1 Spring Bean的后处理器

一切始于 Spring 容器的 Bean 创建和初始化过程。Spring 通过一系列的 BeanPostProcessor 接口实现类来增强 Bean 的功能,其中与事务管理密切相关的便是 AbstractAutoProxyCreator的子类,如 AnnotationAwareAspectJAutoProxyCreator。这个类负责扫描并创建代理对象,以便于在运行时织入诸如事务管理这样的切面逻辑。NJL28资讯网——每日最新资讯28at.com

1.2 识别 @Transactional 注解

  • ClassPathScanningCandidateComponentProvider:Spring 首先会使用此类扫描指定包路径下带有特定注解(如@Transactional)的类或方法。
  • AnnotationTransactionAttributeSource:一旦找到带有 @Transactional 注解的类或方法,Spring 会使用 AnnotationTransactionAttributeSource 来解析这些注解,将其转换为事务属性(TransactionAttribute),比如事务的隔离级别、传播行为、超时时间等。

1.3 创建代理对象

  • 对于基于接口的代理,Spring 使用 JDK 的动态代理技术,通过JdkDynamicAopProxy创建代理对象。该代理会检查调用链,并在调用目标方法前插入事务管理的前置逻辑,调用后插入后置逻辑(如提交或回滚事务)。
  • 对于没有实现接口的类,Spring 则利用 CGLIB 库生成目标类的子类作为代理,通过CglibAopProxy 来完成。CGLIB 代理同样能够在目标方法调用的前后插入事务管理代码。

1.4 TransactionInterceptor

  • 在代理对象中,事务管理的具体逻辑是由 TransactionInterceptor(事务拦截器)来执行的。它实现了 MethodInterceptor 接口,因此当代理对象的方法被调用时,会进入invoke(MethodInvocation invocation) 方法。在这个方法内,TransactionInterceptor 根据解析出的事务属性来决定是否开启事务、使用何种传播行为,并最终调用目标方法。

总结下就是,Spring 通过 Bean 的后置处理器在容器初始化阶段自动检测带有 @Transactional 注解的类和方法,并通过动态代理机制为这些组件创建代理对象。代理对象在方法调用时,通过 TransactionInterceptor 这一核心组件,根据注解配置的事务属性来管理事务生命周期,确保事务逻辑的无缝集成。NJL28资讯网——每日最新资讯28at.com

二 事务拦截与执行

2.1 TransactionInterceptor 的作用

TransactionInterceptor 实现了 Spring 的 MethodInterceptor 接口,这意味着它能够拦截方法调用,并在调用前后执行额外的逻辑,即事务管理逻辑。其核心职责包括:NJL28资讯网——每日最新资讯28at.com

  • 识别是否需要事务: 根据目标方法上的 @Transactional 注解(如果有的话)及其属性(如传播行为、隔离级别、超时时间等),决定是否需要启动一个新的事务或加入到现有的事务中。需要注意的是,事务上下文(包括连接信息等)被存储在由 Spring 管理的一个特定的 TransactionSynchronizationManager 中,TransactionSynchronizationManager 内部使用了 ThreadLocal。
  • 事务管理: 在方法调用之前开启事务,调用之后根据方法执行结果提交或回滚事务。这包括异常处理逻辑,即在遇到未被捕获的异常时,确保事务被正确回滚。

2.2 拦截与执行流程

  1. 方法调用前:
  • 事务属性解析: TransactionInterceptor 首先通过TransactionAttributeSource(通常是AnnotationTransactionAttributeSource)获取目标方法的事务属性。
  • 事务开始: 根据解析出的事务属性,决定是否创建新的事务或者加入到当前事务中。如果需要新事务,它会通过事务管理器(如 PlatformTransactionManager 的实现类)来开始事务。
  1. 方法执行:
  • 在事务上下文中执行实际的目标方法。此时,如果目标方法内部抛出了异常,这个异常会被暂存以供后续处理。NJL28资讯网——每日最新资讯28at.com

  1. NJL28资讯网——每日最新资讯28at.com

    方法调用后:NJL28资讯网——每日最新资讯28at.com

    NJL28资讯网——每日最新资讯28at.com

  • 异常处理: 如果方法执行过程中抛出了异常,TransactionInterceptor 会捕获到这个异常,并根据异常类型及事务属性决定是否需要回滚事务。通常,非检查型异常(继承自 RuntimeException 的异常)会导致事务回滚,而检查型异常则不会,除非事务属性特别指定了回滚规则。NJL28资讯网——每日最新资讯28at.com

  • 事务提交或回滚: 如果方法正常结束,或者按事务属性应该提交事务的情况下,事务管理器会提交事务。相反,如果需要回滚,则执行回滚操作。NJL28资讯网——每日最新资讯28at.com

  1. NJL28资讯网——每日最新资讯28at.com

    资源清理: 在事务结束后,确保所有资源被正确释放,比如关闭数据库连接等。NJL28资讯网——每日最新资讯28at.com

    NJL28资讯网——每日最新资讯28at.com

2.3 动态代理的作用

整个过程中,动态代理扮演着关键角色。无论是 JDK 动态代理还是 CGLIB 代理,它们都是在调用真正业务方法之前插入事务拦截逻辑的桥梁。当客户端代码调用代理对象上的方法时,实际上是调用了由 TransactionInterceptor 所控制的代理逻辑,从而透明地在业务逻辑执行前后管理事务。NJL28资讯网——每日最新资讯28at.com

通过这种方式,开发者无需在每个需要事务管理的方法中手动编写开启、提交或回滚事务的代码,极大地简化了开发复杂度,提高了代码的可维护性和可读性。NJL28资讯网——每日最新资讯28at.com

三 多线程环境下的挑战

当 @Transactional 标记的方法内部启动新的线程时,问题就显现了。前面提到,事务拦截使用了 TransactionInterceptor,而 TransactionInterceptor 内部用到了  TransactionSynchronizationManager,TransactionSynchronizationManager 使用 ThreadLocal 来存储事务相关的资源信息,如数据库连接、JMS 会话等。这意味着每个线程都有其独立的事务上下文,确保了事务信息在线程间的隔离。NJL28资讯网——每日最新资讯28at.com

换句话说,Spring 管理的事务上下文是基于调用线程的,新线程并没有继承原线程的 TransactionSynchronizationManager 中的事务上下文。因此,新线程执行的数据库操作实际上是在无事务管理的环境下进行的,这就导致事务失效。NJL28资讯网——每日最新资讯28at.com

那如果非要用多线程怎么办呢?这个时候可以使用编程式事务,首先设置一个全局变量 Boolean,默认是可以提交的 true,在子线程,通过编程式事务的方式去开启事务,然后插入数据,插入完成后,事务先不提交,同时通知主线程,我准备好了,进入等待状态。如果子线程出现异常,那就通知主线程,我这边发生异常,然后自己回滚。NJL28资讯网——每日最新资讯28at.com

最后主线程收集各个子线程的状态,如果有一个线程出现问题,那么全局变量就设置为不可提交false,然后唤醒所有子线程,进行回滚。NJL28资讯网——每日最新资讯28at.com

这里涉及到线程同步可以利用闭锁去实现;当主线程通知各个子线程提交事务的时候,子线程可能在提交的时候出错了,最终导致数据不一致,那么这种时候可能就需要引入重试机制,有了重试机制后,又要去保证幂等性等等。NJL28资讯网——每日最新资讯28at.com

这一套方案下来大伙有没有觉得眼熟,是不是就是分布式事务的处理思路了?NJL28资讯网——每日最新资讯28at.com

所以说,非要在事务中开启多线程也没问题,但是不建议这么做。NJL28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-93354-0.html事务中存在多线程,怎么处理?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 基于 Python 的人脸检测 :人脸识别的前提

下一篇: Fiddler:一个大名鼎鼎的私藏工具

标签:
  • 热门焦点
  • K60 Pro官方停产 第三方瞬间涨价

    虽然没有官方宣布,但Redmi的一些高管也已经透露了,Redmi K60 Pro已经停产且不会补货,这一切都是为了即将到来的K60 Ultra铺路,属于厂家的正常操作。但有意思的是该机在停产之后
  • 7月安卓手机好评榜:三星S23Ultra好评率第一

    性能榜和性价比榜之后,我们来看最后的安卓手机好评榜,数据来源安兔兔评测,收集时间2023年7月1日至7月31日,仅限国内市场。第一名:三星Galaxy S23 Ultra好评率:95.71%在即将迎来新
  • 《英雄联盟》夏季赛总决赛今日开打!JDG对阵LNG首发名单来了 Knight:准备三连冠

    8月5日消息,今日17:00,《英雄联盟》2023LPL夏季赛总决赛将正式开打,由JDG对阵LNG。对两支队伍来说,这场比赛不仅要争夺夏季赛冠军,更要决定谁才是LPL赛区一
  • Automa-通过连接块来自动化你的浏览器

    1、前言通过浏览器插件可实现自动化脚本的录制与编写,具有代表性的工具就是:Selenium IDE、Katalon Recorder,对于简单的业务来说可快速实现自动化的上手工作。Selenium IDEKat
  • 自动化在DevOps中的力量:简化软件开发和交付

    自动化在DevOps中扮演着重要角色,它提升了DevOps的效能。通过自动化工具和方法,DevOps团队可以实现以下目标:消除手动和重复性任务。简化流程。在整个软件开发生命周期中实现更
  • 一文掌握 Golang 模糊测试(Fuzz Testing)

    模糊测试(Fuzz Testing)模糊测试(Fuzz Testing)是通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法。可以用来发现应用程序、操作系统和网络协议等中的漏洞或
  • Python异步IO编程的进程/线程通信实现

    这篇文章再讲3种方式,同时讲4中进程间通信的方式一、 Python 中线程间通信的实现方式共享变量共享变量是多个线程可以共同访问的变量。在Python中,可以使用threading模块中的L
  • 最“俊美”淘宝卖家,靠直播和短视频圈粉,上架秒光,年销3000万

    来源 | 电商在线文|易琬玉编辑|斯问受访店铺:Ringdoll戒之人形图源:微博@御座的黄山、“Ringdoll戒之人形”淘宝店铺有关外貌的评价,黄山已经听累了。生于1985年的他,哪
  • 自律,给不了Keep自由!

    来源 | 互联网品牌官作者 | 李大为编排 | 又耳 审核 | 谷晓辉自律能不能给用户自由暂时不好说,但大概率不能给Keep自由。近日,全球最大的在线健身平台Keep正式登陆港交所,努力
Top