有两个事务,事务1在行上持有S锁,事务2要更新该行,然后事务2等待,然后事务1在该行上也执行更新,这时发生死锁,我想知道是什么原因吗?这里的锁情况如何?
我在mysql5.6版本上进行了以下测试。有一个死锁。
表结构:
</div>
<!-- Mask & flexbox options-->
初始数据:
CREATE TABLE `test` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增',
`uni_id` bigint(20) DEFAULT NULL,
`current_status` int(11) DEFAULT '0' ,
`total` int(11) NOT NULL DEFAULT '0' ,
PRIMARY KEY (`id`),
UNIQUE KEY `uni_id_unique` (`uni_id`),
KEY `uni_id_idx` (`uni_id`),
KEY `current_status_idx` (`current_status`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
按顺序执行以下操作: 1.第一步 交易1:
INSERT INTO `test`(`id`, `uni_id`, `current_status`, `total`) VALUES (1, 1, 0, 1);
start transaction;
select * from test where id=1 lock in share mode;
start transaction;
update test set uni_id=1,total=total+1 where uni_id=1;
然后那只脱发发生了。
死锁信息:
update test set current_status=1 where id=1 and
current_status=0;
答案 0 :(得分:1)
我认为您对实际发生的情况的分析是完全正确的。这是可能的事件版本:
从MySQL documentation:
在这里,FOR SHARE不是一个好的解决方案,因为如果两个用户同时读取计数器,则其中至少有一个在尝试更新计数器时会陷入死锁状态。
该文档建议,一种更好的方法可能是执行SELECT ... FOR UPDATE
:
SELECT * FROM test WHERE id = 1 FOR UPDATE;
UPDATE test SET uni_id = 1, total = total+1 WHERE uni_id = 1;
答案 1 :(得分:0)
我的一个朋友解释了这种情况。
从MYSQL文档:
此处发生死锁,因为客户端A需要X锁才能删除该行。但是,不能授予该锁定请求,因为客户端B已经具有X锁定请求,并且正在等待客户端A释放其S锁定。由于B事先要求X锁,因此A持有的S锁也不能升级为X锁。结果,InnoDB为其中一个客户端生成错误并释放其锁