要我说,多线程事务它必须就是个伪命题!(上)

简介: 要我说,多线程事务它必须就是个伪命题!(上)

别问,问就是不行


分布式事务你应该是知道的。但是这个多线程事务......


没事,我慢慢给你说。


image.png


如图所示,有个小伙伴想要实现多线程事务。


这个需求其实我在不同的地方看到过很多次,所以我才说:这个问题又出现了。


那么有解决方案吗?


在此之前,我的回答都是非常的肯定:毋庸置疑,肯定是没有的。


image.png


为什么呢?


我们先从理论上去推理一下。


来,首先我问你,事务的特性是什么?


这个不难吧?八股文必背内容之一,ACID 必须张口就来:


  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)


那么问题又来了,你觉得如果有多线程事务,那么我们破坏了哪个特性?


多线程事务你也别想的多深奥,你就想,两个不同的用户各自发起了一个下单请求,这个请求对应的后台实现逻辑中是有事务存在的。


这不就是多线程事务吗?


这种场景下你没有想过怎么分别去控制两个用户的事务操作吧?


因为这两个操作之间就是完全隔离的,各自拿着各自的链接玩儿。


所以多个事务之间的最基本的原则是什么?


隔离性。两个事务操作之间不应该相互干扰。


而多线程事务想要实现的是 A 线程异常了。A,B 线程的事务一起回滚。


image.png


事务的特性里面就卡的死死的。所以,多线程事务从理论上就是行不通的。

通过理论指导实践,那么多线程事务的代码也就是写不出来的。

前面说到隔离性。那么请问,Spring 的源码里面,对于事务的隔离性是如何保证的呢?

答案就是 ThreadLocal。

在事务开启的时候,把当前的链接保存在了 ThreadLocal 里面,从而保证了多线程之间的隔离性:


image.png


可以看到,这个 resource 对象是一个 ThreadLocal 对象。

在下面这个方法中进行了赋值操作:

org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin


image.png


其中的 bindResource 方法中,就是把当前链接绑定到当前线程中,其中的 resource 就是我们刚刚说的 ThreadLocal:



image.png


就是每个线程里面都各自玩自己的,我们不可能打破 ThreadLocal 的使用规则,让各个线程共享同一个 ThreadLocal 吧?

铁子,你要是这样去做的话,那岂不是走远了?

所以,无论从理论上,还是代码实现上,我都认为这个需求是不能实现的。

至少我之前是这样想的。

但是事情,稍稍的发生了一点点的变化。


image.png


说个场景,常规实现

任何脱离场景讨论技术实现的行为都是耍流氓。

所以,我们先看一下场景是什么。

假设我们有一个大数据系统,每天指定时间,我们就需要从大数据系统中拉取 50w 条数据,对数据进行一个清洗操作,然后把数据保存到我们业务系统的数据库中。

对于业务系统而言,这 50w 条数据,必须全部落库,差一条都不行。要么就是一条都不插入。

在这个过程中,不会去调用其他的外部接口,也不会有其他的流程去操作这个表的数据。

既然说到一条不差了,那么对于大家直观而言,想到的肯定是两个解决方案:

  1. for 循环中一条条的事务插入。
  2. 直接一条语句批量插入。

对于这种需求,开启事务,然后在 for 循环中一条条的插入可以说是非常 low 的解决方案了。


image.png


效率非常的低下,给大家演示一下。

比如,我们有一个 Student 表,表结构非常简单,如下:



image.png


image.png


这种情况下,我们可以通过下面的链接,模拟插入指定数量的数据:

http://127.0.0.1:8081/insertOneByOne?num=xxx

我尝试了把 num 设置为 50w,让它慢慢的跑着,但是我还是太年轻了,等了非常长的时间都没有等到结果。

于是我把 num 改为了 5000,运行结果如下:

insertOneByOne执行耗时:133449ms,num=5000

一条条的插入 5000 条数据,耗时 133.5 s 的样子。

按照这个速度,插入 50w 条数据得 13350s,大概也是这么多小时:


image.png


这谁顶得住啊。

所以,这方案拥有巨大的优化空间。

比如我们优化为这样批量插入:


image.png


其对应的 sql 语句是这样的:

insert into table ([列名],[列名]) VALUES ([列值],[列值]), ([列值],[列值]);

我们还是通过前端接口调用:


image.png


当我们的 num 设置为 5000 的时候,我页面刷新了 10 次,你看耗时基本上在 200ms 毫秒以内:


image.png


从 133.5s 到 200ms,朋友们,这是什么东西?

这是质的飞跃啊。性能提升了近 667 倍的样子。


image.png


为什么批量插入能有这么大的飞跃呢?

你想啊,之前 for 循环插入,虽然 SpringBoot 2.0 默认使用了 HikariPool,连接池里面默认给你搞 10 个连接。

但是你只需要一个连接,开启一次事务。这个不耗时。

耗时的地方是你 5000 次 IO 呀。

所以,耗时长是必然的。

而批量插入只是一条 sql 语句,所以只需要一个连接,还不需要开启事务。

为啥不用开启事务?

你一条 sql 开启事务有锤子用啊?

那么,如果我们一口气插入 50w 条数据,会是怎么样的呢?

来,搞一波,试一下:

http://127.0.0.1:8081/insertBatch?num=500000


image.png


说你这个包太大了。可以通过设置 max_allowed_packet 来改变包大小。

我们可以通过下面的语句查询当前的配置大小:

select @@max_allowed_packet;


image.png

目录
相关文章
|
监控 安全 数据库
要我说,多线程事务它必须就是个伪命题!(下)
要我说,多线程事务它必须就是个伪命题!(下)
209 0
要我说,多线程事务它必须就是个伪命题!(下)
|
SQL 关系型数据库 MySQL
要我说,多线程事务它必须就是个伪命题!(中)
要我说,多线程事务它必须就是个伪命题!(中)
260 0
要我说,多线程事务它必须就是个伪命题!(中)
|
1月前
|
Java
如何在Java中进行多线程编程
Java多线程编程常用方式包括:继承Thread类、实现Runnable接口、Callable接口(可返回结果)及使用线程池。推荐线程池以提升性能,避免频繁创建线程。结合同步与通信机制,可有效管理并发任务。
127 6
|
4月前
|
Java API 微服务
为什么虚拟线程将改变Java并发编程?
为什么虚拟线程将改变Java并发编程?
287 83
|
20天前
|
Java 调度 数据库
Python threading模块:多线程编程的实战指南
本文深入讲解Python多线程编程,涵盖threading模块的核心用法:线程创建、生命周期、同步机制(锁、信号量、条件变量)、线程通信(队列)、守护线程与线程池应用。结合实战案例,如多线程下载器,帮助开发者提升程序并发性能,适用于I/O密集型任务处理。
178 0
|
2月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
186 16
|
6月前
|
机器学习/深度学习 消息中间件 存储
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
227 0
|
9月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
154 26
|
9月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
164 17
|
11月前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
633 2

热门文章

最新文章