mysql - innoDB 如何获取多行和子查询的锁?
问题描述
当我们的服务器处理两个特定请求 1 和 2 时,我们遇到了死锁情况。
数据库有表order_item
和product
. 对order_item
有外键约束product
。
(1) 启动手动 SQL 事务并插入多个order_items
. product
因此,此事务按顺序请求对各个 PRIMARY 索引进行多个锁定。
INSERT INTO order_item (...) VALUES (...)
INSERT INTO order_item (...) VALUES (...)
...
(2) 是一个大的 UPDATE 语句,它更新大多数product
s,但也扫描order_item
s 和其他一些表。
UPDATE product
LEFT JOIN (SELECT ... FROM order_item ... INNER JOIN product ...)
...
现在我们陷入了僵局。SHOW ENGINE INNODB STATUS
表明两个事务都持有锁product
并等待更多锁,即使 (2) 实际上是单个 SQL 语句。
*** (1) TRANSACTION:
TRANSACTION 39503904, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 52 lock struct(s), heap size 8400, 45 row lock(s), undo log entries 22
MySQL thread id 3651,操作系统线程句柄 123145451790336,查询 id 1271704 localhost 根更新
INSERT INTOorder_item
...
*** (1) HOLDS THE LOCK(S):
记录锁空间 id 317598 页号 30 n 位 80 表product
trx 的索引 id 39503904 锁模式 S 锁定记录但不锁定间隙
*** (1) 等待此锁定被授予:
记录锁定空间 id 317598 页号 29 n 位 72 表product
trx 的索引主 id 39503904 锁定模式 S 锁定记录但不等待间隙\
*** (2) TRANSACTION:
TRANSACTION 39503901, ACTIVE 0 sec fetching rows
mysql tables in use 4, locked 4
LOCK WAIT 495 lock struct(s), heap size 73936, 21867 row lock(s), undo log entries 184
MySQL thread id 3647,OS 线程句柄 123145450577920,查询 id 1271692 localhost root
UPDATEproduct
...
*** (2) HOLDS THE LOCK(S):
记录锁空间 id 317598 页号 29 n 位 72 表product
trx 的索引 id 39503901 lock_mode X
*** (2) 等待此锁定被授予:
记录锁定空间 id 317598 页号 30 n 位 80 表product
trx 的索引主 id 39503901 lock_mode X waiting\
据我了解,死锁转储表示作为单个 UPDATE 语句的事务 (2) 也尝试按顺序获取锁,即使它是单个语句。这就是内部请求多行锁的方式吗?是因为子查询(连接)吗?我在文档中找不到这个细节。我们使用的是 MySQL 8.0.19。
解决方案
推荐阅读
- c++ - 输入字符变量的问题
- node.js - 不和谐.js | 通过 DM 请求输入
- java - 避免使用 Java 中数据类的继承进行动态类型转换
- php - Microsoft Teams + PHP cURL - 向特定频道发送消息
- javascript - Laravel 数据到 javascript 这可能是不安全的并且是一个开放的漏洞吗?
- python - Google App Engine:使用 keras/tensorflow/flask 加载资源失败
- swift - 使用 SwiftUI 在 Xcode 11 上预览 EXC_BAD_ACCESS、KERN_PROTECTION_FAILURE
- git - 任何想法来控制设置文件?
- scala - 如何将csv文件中可用的列名作为标题分配给orc文件
- mysql - 如何在 vue js 和 Laravel 中显示来自多个表的数据?