MySQL 如何避免 RC 隔离级别下的 INSERT 死锁?

Mysql:RC隔离级别下如何提高并发? 意思是插入意向锁准备插入之前遇到了间隙锁,但是隔离级别是RC,按照网上的说法和文档,RC隔离级别是不会出现Gap Lock的,后面发现表中若有唯一索引,RC隔离级别下并发也会导致Gap Lock,去掉唯一索引,跑批就没问题了。Mysql是支持行锁的,但是行锁只是针对索引列,若删除条件未加索引会导致走表锁,这样就会造成死锁。索引建了之后运行还是报错死锁,打开死锁日志。 阅读详情

本文分析了 INSERT 及其变种(REPLACE/INSERT ON DUPLICATE KEY UPDATE)的几个场景的死锁及如何避免。

作者:张洛丹,DBA 数据库技术爱好者~

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文共 3200 字,预计阅读需要 10 分钟。

说在前面

本文分析了 INSERT 及其变种(REPLACE/INSERT ON DUPLICATE KEY UPDATE)的几个场景的死锁及如何避免:

  • 场景一:INSERT 唯一键冲突
  • 场景二/三:REPLACE INTO 唯一键冲突(来自线上业务)
  • 场景四:INSERT 主键冲突(来自官方案例)

其实 Google 一番,也会有大量这样的文章。本文只是就几个场景进行了分析,不过一遍走下来,对 INSERT 加锁情况、如何导致的死锁也就掌握了,个人能力有限,如文中内容有错误和纰漏,也欢迎大佬指出。

有兴趣的就继续往下看吧~

回顾行锁

在此之前,先浅浅回顾一下 InnoDB 中的行锁类型。

记录锁(RECORD LOCK)

对索引记录加锁。

间隙锁(GAP LOCK,也叫范围锁)

对索引记录的所在间隙加锁,在 RR 隔离级别下,用于解决幻读的问题(实际上在 RC 隔离级别下,也会产生间隙锁)。

S 间隙锁和 X 间隙锁是兼容的,不同的事务可以在同一个间隙加锁。

NEXT-KEY 锁

相当于 RECORD LOCK + GAP LOCK。

插入意向锁(INSERT INTENTION LOCK)

GAP 锁的一种,在执行 INSERT 前,如果待插入记录的下一条记录上被加了 GAP 锁,则 INSERT 语句被阻塞,且生成一个插入意向锁。

仅会被 GAP 锁阻塞。

隐式锁

新插入的记录,不生成锁结构,但由于事务 ID 的存在,相当于加了隐式锁;别的事务要对这条记录加锁前,先帮助其生成一个锁结构,然后再进入等待状态。


这里产生死锁的关键就是 GAP 锁。GAP 锁是在 RR 隔离级别下用于解决幻读问题,但是 RC 隔离级别下,在重复键检查和外键检查时也会用到。

再浅浅回顾一下 INSERT 语句加锁类型:

  1. 被 GAP 锁阻塞时,生成一个插入意向锁。
  2. 遇到重复键冲突时
    • 主键冲突,产生 S 型记录锁(RR 和 RR 隔离级别,实际上在 INSERT 阶段时还是会请求 GAP 锁)。
    • 唯一键冲突,产生 S 型 NEXT-KEY 锁(RR 和 RR 隔离级别)。

注意:INSERT 语句正常执行时,不会生成锁结构。

另外,对于 INSERT ... ON DUPLICATE KEY UPDATE 和 REPLACE 稍有一些不同:

锁类型的不同

INSERT ... ON DUPLICATE KEY UPDATE 和 REPLACE 如果遇到重复键冲突。

  • 如果是主键冲突,加 X 型记录锁(RR 和 RR 隔离级别,实际上在 INSERT 阶段时还是会请求 GAP 锁)。
  • 如果是唯一键冲突,加 X 型 NEXT-KEY 锁(RR 和 RR 隔离级别)。

锁范围不同

  • INSERT 和 INSERT ... ON DUPLICATE KEY UPDATE 在插入或 UPDATE 的行上加 NEXT-KEY 锁。
  • REPLACE 在加 NEXT-KEY 锁时,会在 REPLACE 的记录及其下一条记录上加 NEXT-KEY 锁。

    这里和官方文档描述有些不同。如下,官方仅说了会在被 REPLACE 的行上加 NEXT-KEY 锁,但是测试下来其下一行也会加 NEXT-KEY 锁,具体见后文的场景。

最后浅浅回顾一下死锁的产生条件以及观测手段:

死锁的产生条件

两个或两个以上事务,互相等待对方持有的锁,且持有对方需要的锁,从而造成循环等待。

死锁观测手段

performance_schema.data_locks 查看会话产生的锁结构信息。

SELECT ENGINE_TRANSACTION_ID, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA FROM performance_schema.data_locks;

show engine innodb status 查看死锁信息。

正式开始

正式开始前还是要说一下基本的环境信息:

  • MySQL 8.0.32
  • transaction_isolation:READ-COMMITTED

准备数据

每个案例初始数据都是这些。

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (
    id INT NOT NULL AUTO_INCREMENT,
    a INT NULL,
    b INT NULL,
    PRIMARY KEY (id),
    UNIQUE INDEX uk_a (a ASC)
);
INSERT INTO t1 (id, a, b) VALUES (1, 10, 0);
INSERT INTO t1 (id, a, b) VALUES (2, 20, 0);
INSERT INTO t1 (id, a, b) VALUES (3, 30, 0);
INSERT INTO t1 (id, a, b) VALUES (4, 40, 0);
INSERT INTO t1 (id, a, b) VALUES (5, 50, 0);

场景一

时刻session1session2
T1BEGIN;
INSERT INTO t1(a,b) VALUES (35,0);
T2BEGIN;
INSERT INTO t1(a,b) VALUES (35,0); --被阻塞
T3INSERT INTO t1(a,b) VALUES (33,0)
T4DEADLOCK

不同时刻持有锁状态如下:

说明:示意图中仅画出我们分析的唯一索引上的锁,实际上在对唯一索引加上锁后,还会对对应的聚簇索引加记录锁,对主键索引但这里不去体现了,下文同。

过程解说

T1 时刻

session1 插入记录成功,此时对应的索引记录被隐式锁保护,未生成锁结构。

T2 时刻

session2 插入记录检测到插入值和 session1 唯一键冲突。

  • session2 帮助 session1 对 a=35 的记录产生了一个显式的锁结构。
  • session2 自身产生 S 型的 NEXT-KEY LOCK,请求范围为 (30,35],但是其只能获取到 (30,35) 的 GAP LOCK,而被 session1 的 a=35 的记录锁阻塞。
mysql> SELECT ENGINE_TRANSACTION_ID, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA FROM performance_schema.data_locks;
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
| ENGINE_TRANSACTION_ID | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA |
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
|               xxxxxx2 | t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx2 | t1          | uk_a       | RECORD    | S             | WAITING     | 35, 7     |
|               xxxxxx1 | t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx1 | t1          | uk_a       | RECORD    | X,REC_NOT_GAP | GRANTED     | 35, 7     |
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
4 rows in set (0.01 sec)
T3 时刻
  • session1 插入 a=33,被 session2 (30,35)间隙锁阻塞。

至此,形成闭环锁等待,死锁条件达成:

  • session1 持有 session2 需要的 a=35 记录锁,且请求 session2 持有的 (30,35) GAP 锁。
  • session2 持有 session1 需要的 (30,35) GAP 锁,且请求 session1 持有的记录锁。

下面是打印的死锁日志。

针对该场景的死锁该如何避免:

  • 在一个事务中的 INSERT 按照主键或唯一键的顺序增序插入,即 session1 可以先插入 a=33 的记录,再插入 a=35 的记录,可一定程度避免受到 GAP 锁的影响。
  • 一个事务中只插入一行记录,且尽快提交。

场景二

时刻session1session2session3
T1BEGIN; REPLACE INTO t1 (a, b) VALUES (40, 1);
T2BEGIN; REPLACE INTO t1 (a, b) VALUES (30, 1); -- 被阻塞
T3BEGIN; REPLACE INTO t1 (a, b) VALUES (40, 1);  -- 被阻塞
T4COMMIT;
T52 rows affected;DEADLOCK,ROLLBACK;

不同时刻持有锁状态如下:

过程解说

T1 时刻

session1 检测到唯一键冲突,对 REPLACE 的记录和其下一条记录加 X 型 NEXT-KEY 锁,即锁范围为 (30,40],(40,50]。

注意:这里和 INSERT 区分,INSERT 遇到唯一键冲突被阻塞时,在插入的记录上加的 NEXT-KEY 锁,这里 REPLACE 是在插入记录和下一条记录上加的 NEXT-KEY 锁(官方文档描述似乎有欠妥当)。

锁情况

mysql> SELECT ENGINE_TRANSACTION_ID, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA FROM performance_schema.data_locks;
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
| ENGINE_TRANSACTION_ID | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA |
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
|               xxxxxx1| t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx1| t1          | uk_a       | RECORD    | X             | GRANTED     | 40, 4     |
|               xxxxxx1| t1          | uk_a       | RECORD    | X             | GRANTED     | 50, 5     |
|               xxxxxx1| t1          | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 4         |
|               xxxxxx1| t1          | uk_a       | RECORD    | X,GAP         | GRANTED     | 40, 10    |
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
5 rows in set (0.00 sec)
T2 时刻

session2 遇到唯一键冲突,对 REPLACE 的记录和其下一条记录加 X 型 NEXT-KEY 锁,即锁范围是 (20,30],(30,40],对 (20,30],(30,40) 加锁成功,但是等待 session1 a=40 的记录锁。

mysql> SELECT ENGINE_TRANSACTION_ID, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA FROM performance_schema.data_locks;
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
| ENGINE_TRANSACTION_ID | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA |
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
|               xxxxxx2 | t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx2 | t1          | uk_a       | RECORD    | X             | GRANTED     | 30, 3     |
|               xxxxxx2 | t1          | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 3         |
|               xxxxxx2 | t1          | uk_a       | RECORD    | X             | WAITING     | 40, 4     |
|               xxxxxx1 | t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx1 | t1          | uk_a       | RECORD    | X             | GRANTED     | 40, 4     |
|               xxxxxx1 | t1          | uk_a       | RECORD    | X             | GRANTED     | 50, 5     |
|               xxxxxx1 | t1          | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 4         |
|               xxxxxx1 | t1          | uk_a       | RECORD    | X,GAP         | GRANTED     | 40, 10    |
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
9 rows in set (0.00 sec)
T3 时刻

session3 请求的锁类型和 session1 相同,锁范围为(30,40],(40,50],在获取(30,40] NEXT-KEY 锁时,只获取到了(30,40) GAP 锁,等待 session1 a=40 的记录锁。

注意:这里还未对(40,50] 加上锁,InnoDB 行锁是逐行获取的,无法获取到则被阻塞。

锁情况

mysql> SELECT ENGINE_TRANSACTION_ID, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA FROM performance_schema.data_locks;
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
| ENGINE_TRANSACTION_ID | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA |
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
|               xxxxxx3 | t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx3 | t1          | uk_a       | RECORD    | X             | WAITING     | 40, 4     |
|               xxxxxx2 | t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx2 | t1          | uk_a       | RECORD    | X             | GRANTED     | 30, 3     |
|               xxxxxx2 | t1          | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 3         |
|               xxxxxx2 | t1          | uk_a       | RECORD    | X             | WAITING     | 40, 4     |
|               xxxxxx1 | t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx1 | t1          | uk_a       | RECORD    | X             | GRANTED     | 40, 4     |
|               xxxxxx1 | t1          | uk_a       | RECORD    | X             | GRANTED     | 50, 5     |
|               xxxxxx1 | t1          | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 4         |
|               xxxxxx1 | t1          | uk_a       | RECORD    | X,GAP         | GRANTED     | 40, 10    |
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
11 rows in set (0.01 sec)
T4 时刻
  • session1 提交后,持有的锁释放。
  • session2 获取到 a=40 的记录锁,至此,session2 持有的锁为 (20,30],(30,40] NEXT-KEY 锁 ;session2获取到锁后,执行插入操作,由于插入的间隙是 (20,40),被 session3 的 (30,40) GAP 锁阻塞,产生插入意向锁,并进入等待状态。

至此,形成闭环锁等待,死锁条件达成:

  • session2 持有 (20,30],(30,40] NEXT-KEY 锁,请求插入意向锁,被 session3 的 (30,40) GAP 锁阻塞。
  • session3 持有阻塞 session2 的 (30,40) GAP 锁,请求 sesion2 持有的 a=40 记录锁。

下面是打印的死锁日志。

场景三

时刻session1session2session3
T1BEGIN; SELECT * FROM t1 WHERE a=40 for UPDATE;
T2BEGIN; REPLACE INTO t1 (a, b) VALUES (30, 1);-- 被阻塞
T3BEGIN; REPLACE INTO t1 (a, b) VALUES (40, 1); -- 被阻塞
T4COMMIT;
T52 rows affected;DEADLOCK,ROLLBACK;

不同时刻持有锁状态如下:

该场景和场景二死锁情况基本相同,只是 session1 持有锁类型不同,就不一一解说了。

下面是打印的死锁日志。

针对场景二和场景三的死锁该如何避免?

从前面的分析中,可以看到在唯一键冲突时,INSERT、INSERT ... ON DUPLICATE KEY UPDATE 的加锁范围要比 REPLACE 加锁范围小,在该场景下,可使用 INSERT ... ON DUPLICATE KEY UPDATE 代替 REPLACE 来避免死锁,有兴趣的可以自己测试下。

场景四

说明

  • 本案例测试主键冲突的情况,先删除了表上的唯一键,避免干扰。
  • 对于唯一键冲突的该种场景下同样会产生死锁,死锁情况相同,有兴趣可自行验证。
时刻session1session2session3
T1BEGIN;INSERT INTO t1 (id,a, b) VALUES (6,60, 0);
T2BEGIN;INSERT INTO t1 (id,a, b) VALUES(6,70, 0); --被阻塞
T3BEGIN;INSERT INTO t1 (id,a, b) VALUES(6,80, 0);-- 被阻塞
T4ROLLBACK;
T51 rows affected;DEADLOCK,ROLLBACK;

锁情况

在 T1、T2、T3 阶段锁情况如下,此时并没有 GAP 锁,是记录锁,相应的锁状态如下:

mysql>  SELECT ENGINE_TRANSACTION_ID, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA FROM performance_schema.data_locks;
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
| ENGINE_TRANSACTION_ID | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA |
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
|               xxxxxx3 | t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx3 | t1          | PRIMARY    | RECORD    | S,REC_NOT_GAP | WAITING     | 6         |
|               xxxxxx2 | t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx2 | t1          | PRIMARY    | RECORD    | S,REC_NOT_GAP | WAITING     | 6         |
|               xxxxxx1 | t1          | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|               xxxxxx1 | t1          | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 6         |
+-----------------------+-------------+------------+-----------+---------------+-------------+-----------+
6 rows in set (0.00 sec)
T4 时刻

session1 ROLLBACK,session2 和 session3 都获取到了 S 锁,在 INSERT 阶段,却产生了 NEXT-KEY 锁,锁范围为 (5,supremum]。

至此,形成闭环锁等待,死锁条件达成: session2 和 session3 分别想要在插入的间隙 (5,supremum) 获得插入意向锁,但分别被对方持有的 GAP 锁阻塞。

下面是打印的死锁日志。

触发死锁后,我们再看锁持有情况。

此时 session2 持有 (5,supremum),再插入该范围内的记录都会被阻塞了。

mysql>  SELECT ENGINE_TRANSACTION_ID, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA FROM performance_schema.data_locks;
+-----------------------+-------------+------------+-----------+--------------------+-------------+------------------------+
| ENGINE_TRANSACTION_ID | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE          | LOCK_STATUS | LOCK_DATA              |
+-----------------------+-------------+------------+-----------+--------------------+-------------+------------------------+
|               xxxxxx2 | t1          | NULL       | TABLE     | IX                 | GRANTED     | NULL                   |
|               xxxxxx2 | t1          | PRIMARY    | RECORD    | S                  | GRANTED     | supremum pseudo-record |
|               xxxxxx2 | t1          | PRIMARY    | RECORD    | X,INSERT_INTENTION | GRANTED     | supremum pseudo-record |
|               xxxxxx2 | t1          | PRIMARY    | RECORD    | S,GAP              | GRANTED     | 6                      |
+-----------------------+-------------+------------+-----------+--------------------+-------------+------------------------+
4 rows in set (0.00 sec)

小结

从前面的实验中可以看到无论是 INSERT 还是 REPLACE,在高并发的情况下由于唯一键的存在,即使在 RC 隔离级别下,仍然有较大概率会触发到死锁。当前只能在业务端做好容错处理,以下是一些小建议来减少或避免 INSERT 死锁:

  1. RC 隔离级别相较 RR 隔离级别产生死锁的概率小,但仍不可避免。
  2. INSERT ... ON DUPLICATE KEY UPDATE 比 REPLACE 产生死锁的几率小且更安全高效。
  3. 并发事务按照相同的顺序处理数据。
  4. 事务尽快提交,避免大事务、长事务。

另外,通过前面的实验,大家可能会有以下疑问:

  1. 为什么 RC 隔离级别要使用 GAP 锁?
  2. 为什么主键和唯一键的处理方式不同?
  3. ...???

有兴趣的可以到下面文章寻找答案: http://mysql.taobao.org/monthly/2022/05/02/ 更多技术文章,请访问:https://opensource.actionsky.com/

关于 SQLE

爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。

SQLE 获取

类型地址
版本库https://github.com/actiontech/sqle
文档https://actiontech.github.io/sqle-docs/
发布信息https://github.com/actiontech/sqle/releases
数据审核插件开发文档https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
Arcgis栅格裁剪批处理工具 阅读详情

相关推荐

i茅台APP加密参数逆向分析:MT-Device-ID与mt-v生成算法

在移动应用安全领域,参数加密是防止API滥用的重要手段。通过对通信协议的逆向分析,可以揭示加密参数的生成原理,这对理解移动应用安全机制具有重要意义。以i茅台APP为例,其关键接口使用了MT-Device-ID和mt-v两个加密参数,前者基于设备硬件信息生成,后者则通过动态签名机制确保请求时效性。这类技术广泛应用于电商、金融等需要高安全性的场景。通过抓包工具和逆向工程手段,可以还原出从设备指纹生成到动态签名的完整技术链条,其中涉及MD5、SHA256等常见哈希算法的应用。掌握这些加密参数的生成逻辑,不仅有助于

weixin_28568819的博客 320

Mysql什么操作会涉及到锁?

Mysql什么操作会涉及到锁

西瓜的博客 1297

带标签的PHM2009齿轮箱数据集

PHM2009附加数据集—带标签的齿轮箱数据集,可用于测试算法

qq_39379705的博客 4873

mysql insert加锁机制

insert锁

duoyasong5907的博客 1130

dq轴坐标系下的电路方程

dq轴坐标系下的电路方程 dq轴坐标系是一种常见的电路方程,但是再dq轴坐标系下电路元件的电压电流dq轴存在一定的耦合,本文针对三相电路推导了dq轴坐标系下的电路电路方程进行一个推导,首先先列出来派克变换的公式 派克变换 [AdAqA0]=23[cos⁡(θ)cos⁡(θ−2π/3)cos⁡(θ+2π/3)−sin⁡(θ)−sin⁡(θ−2π/3)−sin⁡(θ+2π/3)1/21/21/2][AaAbAc]\left[\begin{array}{c}A_d\\A_q\\A_0 \end{array}\ri

Mr.Young的博客 1万+

libfacedetection 框架阅读及扩展经验

libfacedetection 框架源码解析与扩展心得1. libfacedetection 框架简介2. 源码解析2.1 facedetectcnn.h2.2 facedetectcnn.cpp2.3 facedetectcnn-model.cpp3. 其他层的扩展--depthwise convolution 前段时间因为工作需要,对libfacedetection框架做了些扩展,在阅读源...

weixin_42616332的博客 1500

MySQL 中的 INSERT 是怎么加锁的?

热心网友在评论中提出的一个问题,我还是彻底被问蒙了。

m0_38048955的博客 2467

【液晶专题】从外挂到In-Cell/ On-Cell/ OGS再也不会傻傻分不清楚了

触控技术经历了从外挂式到内嵌式的革新,主要方案包括外挂式(Out-Cell)、OGS、On-Cell和In-Cell。

一点硬件 1252

MySQL——插入加锁/唯一索引插入死锁/批量插入效率

本篇主要介绍MySQL跟加锁相关的一些概念、MySQL执行插入Insert时的加锁过程、唯一索引下批量插入可能导致的死锁情况,以及分别从业务角度和MySQL配置角度介绍提升批量插入的效率的方法;

娜娜米的博客 1万+

[Dify] HTTP 请求节点总是调不通?先把请求头、参数、变量和返回 JSON 拆开查

这篇文章围绕 Dify HTTP 请求节点调不通、接口能通但流程不稳定、返回 JSON 后续节点读不到等问题展开,从 Method、URL、Header、Body、变量映射和返回字段提取几个角度梳理排查顺序。适合正在把 Dify Workflow 接入企业微信、CRM、工单系统或内部接口的读者阅读,帮助你把接口调用从一次性跑通推进到可复用、可验证的业务流程。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 3944

让 Claude Code 接管 SAP 事务流, 用 Python 和 SAP GUI Scripting 做一个真正能干活的 AI Agent

摘要:SAP系统自动化面临的核心瓶颈在于繁琐的GUI操作而非分析能力不足。通过整合Claude AI、Python和SAP GUI Scripting技术,可构建能直接操作SAP界面的智能代理。该方案利用SAP官方提供的脚本接口,实现事务码执行、界面导航、数据提取等自动化操作,特别适用于DMLT过账引擎等复杂错误分析场景。相比传统SQL导出方案,这种GUI级自动化能处理树控件、ALV表格等复杂界面元素,且无需额外API开发,直接在现有SAP GUI会话上工作,在保持原有权限体系的同时显著提升效率。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 321

MySQL 必现之死锁

MySQL 必现之死锁

wzy0623的专栏 4183

OpenCV-Python实战(3)——OpenCV中绘制图形与文本

OpenCV 是一个的跨平台计算机视觉库,实现了图像处理和计算机视觉方面的很多通用算法。本文介绍了 OpenCV 提供的与绘制图形和文本相关的函数。在图形方面,我们了解了如何绘制基本图形(直线、矩形和圆形等)以及高级图形(剪裁线、箭头、椭圆和多边形)。在文本方面,我们了解了如何绘制文本以及 OpenCV 库中的所有可用字体。

盼小辉丶的博客 2万+

mysql delete in死锁_MySQL死锁案例分析一(先delete,再insert,导致死锁)

一、死锁案例MySQL版本:Percona MySQL Server 5.7.19隔离级别:可重复读(RR)业务逻辑:并发下按某个索引字段先delete记录,再insert记录比如:begin;delete from tb where order_id = xxx;insert into tb(order_id) values(xxx);commit;二、MySQL锁基本概念S:共享锁(行级锁)X...

weixin_31741271的博客 472

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

深入探索MySQL锁机制:揭秘死锁原因与RC隔离级别下的事务处理

本文分析了MySQL中RC隔离级别下INSERT操作的死锁问题,探讨了不同场景下死锁的产生原因,并提供了避免死锁的策略。建议包括按顺序插入数据、减少事务大小、使用INSERT...ON DUPLICATE KEY UPDATE代替REPLACE,以及快速提交事务,以降低死锁风险并提升数据库并发性能。

若明天不见 1826

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

mysql insert 时出现Deadlock死锁场景分析

案例一: 有一张表A,先更新,如果影响行数为0,则执行INSERT插入数据。很常见的场景,在生产上也跑了很久,没有出现什么问题。但是有一次在测试环境做压测时居然出现了死锁,Deadlock found when trying to get lock; try restarting transaction 因为对mysql锁不熟悉,为什么insert也会死锁,不是一般在update的时候会死锁吗?...

huangdi1309的博客 9214

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

MySql 死锁

MySql 死锁一、什么是死锁InnoDB存储引擎定义了四种类型的行锁隔离等级对加锁的影响当前数据对加锁的影响二、为什么会形成死锁两阶段锁协议产生死锁的四个必要条件三、MySQL 如何处理死锁?杀死进程MySQL表间隙锁排他锁共享锁分析行锁定行锁优化四、如何避免发生死锁1.对索引加锁顺序的不一致很可能会导致死锁;2.Gap 锁往往是程序中导致死锁的真凶;3.为表添加合理的索引,如果不走索引将会为表的每一行记录加锁,死锁的概率就会大大增大;4.我们知道 MyISAM 只支持表锁,它采用一次封锁技术来保证事务之

wgchen 5106

Mysql死锁

mysql死锁分类、产生场景、解决方法

分享日常学习和工作中遇到的技术难点 1034

INSERT语句引发的死锁

两条一样的INSERT语句竟然引发了死锁,这究竟是人性的扭曲,还是道德的沦丧,让我们不禁感叹一句:卧槽!这也能死锁,然后眼中含着悲催的泪水无奈的改起了业务代码。 好的,在深入分析为啥两条一样的INSERT语句也会产生死锁之前,我们先介绍一些基础知识。 准备一下环境 为了故事的顺利发展,我们新建一个用了无数次的hero表: CREATE TABLE hero ( number INT AUTO_INCREMENT, name VARCHAR(100), country var

weixin_64314555的博客 4947

MySQL5.7并发INSERT ON DUPLICATE KEY UPDATE导致死锁

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33722405的博客 5022

mysql大批量并发insert查看死锁_Mysql死锁场景三(普通insert并发插入)

数据准备(与其他场景一样):create table t(c1 int primary key, c2 int, c3 int, c4 int, unique index i_c2(c2), index i_c3(c3));insert into t values (10, 11, 12, 13), (20, 21, 22, 23), (30, 31, 32, 33), (40, 41, 42, ...

weixin_39629467的博客 877

记录一次Mysql死锁事件(由Insert与uniqueKey导致)

| 导语记录一次于2023年01月23日遇到的死锁问题。1、基础1.1 数据库隔离级别1.1.1RCREAD COMMITTED:只能读取已经提交的数据;此时:允许幻读和不可重复读,但不允许脏读,所以RC隔离级别要求解决脏读;1.1.2RRREPEATABLE READ:同一个事务中多次执行同一个select,读取到的数据没有发生改变;此时:允许幻读,但不允许不可重复读和脏读,所以RR隔离级别要求...

Diligence is the mother of success. 1057

mysql insert批量死锁_Mysql 死锁场景一(insert on duplicate key)

数据准备:create table t(c1 int primary key, c2 int, c3 int, c4 int, unique index i_c2(c2), index i_c3(c3));insert into t values (10, 11, 12, 13), (20, 21, 22, 23), (30, 31, 32, 33), (40, 41, 42, 43);表名t,c...

weixin_28993425的博客 1390

从RR到RC:解析大厂数据库隔离级别变革的背后逻辑

为什么大厂用RC隔离级别

一条大河 992

【mysql】【实战】[死锁]----死锁是怎么形成的?怎么避免?怎么解决?怎么排查?

死锁的本质是“资源竞争顺序混乱”,核心解决思路是规范访问顺序、缩短锁持有时间、减少锁范围。通过死锁日志定位具体冲突点,结合业务逻辑优化事务和 SQL,可有效降低死锁概率。对于偶发死锁,应用层重试是简单有效的补救措施。

记录生活 727

mysql delete in死锁_MySQL死锁案例分析一(先delete,再insert,导致死

一、死锁案例MySQL版本:Percona MySQL Server 5.7.19隔离级别:可重复读(RR)业务逻辑:并发下按某个索引字段先delete记录,再insert记录比如:begin;delete from tb where order_id = xxx;insert into tb(order_id) values(xxx);commit;二、MySQL锁基本概念S:共享锁(行级锁)X...

weixin_28726391的博客 1322
上一篇: MySQL 8 的复制可观测性
下一篇: OceanBase 单机租户最多能支持多少分区?
爱可生开源社区
博客等级 码龄8年 1936粉丝 1004原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值