这种僵局会如何发生?
Posted
技术标签:
【中文标题】这种僵局会如何发生?【英文标题】:How would this deadlock happens? 【发布时间】:2019-05-26 17:37:17 【问题描述】:最近在处理一个SQL问题,我有两个事务,事务A先拿到Next-Key Locks,然后事务B尝试获取同一个锁,所以一直在等待,然后事务A尝试获取插入意向锁,死锁就发生了。但我很困惑为什么会发生这种情况?
这是我的表结构:
CREATE TABLE `changeset` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT',
`userId` int(10) NOT NULL COMMENT,
`documentId` varchar(20) NOT NULL,
`memberId` bigint(13) NOT NULL,
`createTime` bigint(13) NOT NULL,
`version` bigint(13) NOT NULL COMMENT,
`changesets` mediumtext,
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_documentId_version` (`documentId`,`version`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=85771623 DEFAULT CHARSET=utf8
这是我的死锁日志:
(1) 交易:
TRANSACTION 22640,ACTIVE 66 秒开始索引读取
mysql 表正在使用 1,已锁定 1
LOCK WAIT 2 个锁结构,堆大小 1136,1 行锁
MySQL 线程 id 209,操作系统线程句柄 123145559986176,查询 id 6204 localhost root 发送数据
select * from changeset where documentId = '7oO5C_v' and version >= 13 for update
(1) 等待授予此锁定:
RECORD LOCKS 空间 id 107 页号 15 n 位 704 索引 uniq_documentId_version 表
test
.changeset
trx id 22640 lock_mode X 等待记录锁,堆号 2 物理记录:n_fields 3;紧凑的格式; 信息位 0
0: 长度 7;十六进制 3976735431644a; asc 9vsT1dJ;;
1: 长度 8;十六进制 8000000000000000;升序;;
2: 长度 4;十六进制 051cbef7;升序;;
(2) 交易:
事务 22639,正在插入 95 秒
mysql 表正在使用 1,已锁定 1
6 个锁结构,堆大小 1136,4 行锁,撤消日志条目 1
MySQL 线程 id 212,操作系统线程句柄 123145561657344,查询 id 6210 本地主机根更新
insert into changeset values (0, 9, '7oO5C_v', 814, 1, 13, 'x')
(2) 持有锁:
RECORD LOCKS 空间 id 107 页号 15 n 位 704 索引 uniq_documentId_version 表
test
.changeset
trx id 22639 lock_mode X记录锁,堆号 2 物理记录:n_fields 3;紧凑的格式; 信息位 0
0: 长度 7;十六进制 3976735431644a; asc 9vsT1dJ;;
1: 长度 8;十六进制 8000000000000000;升序;;
2: 长度 4;十六进制 051cbef7;升序;;
(2) 等待授予此锁定:
RECORD LOCKS 空间 id 107 页号 15 n 位 704 索引 uniq_documentId_version 表
test
.changeset
trx id 22639 lock_mode X 在记录插入意图等待之前锁定间隙记录锁,堆号 2 物理记录:n_fields 3;紧凑的格式; 信息位 0
0: 长度 7;十六进制 3976735431644a; asc 9vsT1dJ;;
1: 长度 8;十六进制 8000000000000000;升序;;
2: 长度 4;十六进制 051cbef7;升序;;
我们回滚交易 (1)
【问题讨论】:
可能也方便我们查看导致死锁的代码?目前看起来很简单“一个事务已开始读取,而另一个事务正在尝试写入正在读取的同一数据区域”? 隔离级别是多少?从日志看,你有两个长时间运行的事务,事务有你描述的那么简单吗? 【参考方案1】:你在你的选择中使用过“(nolock)”吗?
Select * From Table with (nolock)
【讨论】:
以上是关于这种僵局会如何发生?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用第三个列表将列表链接到另一个列表?,有时有效,但发生这种情况时会出错