MySQL InnoDB在选择更新和插入之间发生死锁 背景:
在MySQL 5.7.18中 我有一个名为“test”的表,定义如下:MySQL InnoDB在选择更新和插入之间发生死锁 背景:,mysql,innodb,deadlock,database-deadlocks,Mysql,Innodb,Deadlock,Database Deadlocks,在MySQL 5.7.18中 我有一个名为“test”的表,定义如下: | test | CREATE TABLE `test` ( `id` varchar(255) NOT NULL, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `test_name_x01` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | 它只有一行: id | name 2 |
| test | CREATE TABLE `test` (
`id` varchar(255) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `test_name_x01` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
它只有一行:
id | name
2 | eva
现在,我在REPEATABLE-READ隔离级别启动两个转换,并执行以下命令:
1. T1 : begin;
2. T2 : begin;
3. T2 : select * from test where name='eva' for update;
步骤3需要:IX锁,索引“name”上的下一个键锁(负无穷大,“eva”]
4. T1 : select * from test where name='eva' for update;
步骤4需要:IX锁,索引“name”上的下一个键锁(负无穷大,“eva”]
IX锁与IX兼容,因此T1可以在不释放T2的情况下获取它。
下一个密钥锁实际上包含两个部分:记录X+gap,因为不同的事务可以在一个gap上持有冲突的锁,T1也会在不等待T2的情况下持有gap锁。所以T1只等待T2释放记录锁(在二级索引名称='eva'和聚集索引id='1'上)继续
5. T2 : insert into test values (1, 'eva'); (dead lock, T1 is rolled back)
步骤5:插入需要插入强度锁,这与间隙锁不兼容。因此T2等待T1释放其间隙锁。但同时T1等待T2释放记录X锁
========================================================================
更新后,我发现了我上面的解释无法解释的更有趣的事实。
此外,对于步骤5,在尝试使用不同的ID值后,我有以下观察结果:
如果该表预加载了多个具有不同ID和相同名称“eva”的行,只有在步骤5中尝试插入的ID值小于所有现有行的最小ID时,死锁才是可复制的。
例如,使用
id | name
2 | eva
4 | eva
对于上面的步骤5
insert (0, 'eva') => deadlock
insert (1, 'eva') => deadlock
insert (3, 'eva') => NO deadlock
insert (5, 'eva') => NO deadlock
不要在VARCHARs
中存储不带引号的数字。这会挫败任何使用索引的尝试
更多
一般来说
当可以通过索引识别单行时,只有该行将被“锁定”。单行锁定通常通过“延迟”一个事务直到另一个事务释放其锁来避免死锁
当必须扫描整个表时,可能需要锁定所有行。这可能不允许“延迟”,并导致死锁
无论如何
通过准备重播整个事务来计划死锁。有些死锁是不可避免的
(很抱歉说得含糊不清;这里可能有太多的变体。请修复引号或索引;这样可以避免大多数死锁。)如果允许您插入0或1,主键中2之前的间隔将不再存在。如果插入0,它将变成2个间隔,一个在0之前,一个在2之前……如果插入1,它将变成一个不同的间隔,从下确界到1之前。我不这样认为。MySQL将进行转换。MySQL进行转换,但它向后执行--varchar到number。因此,每个
id
在查找时都会转换为一个数字,以便与查询中未引用的数字进行比较。因此,您不会从id
上获得任何索引的好处。好的。但这与我面临的死锁问题有关吗?引用id
后的问题完全相同>在insert
语句中。@superluli-参见我的添加。
insert (0, 'eva') => deadlock
insert (1, 'eva') => deadlock
insert (3, 'eva') => NO deadlock
insert (5, 'eva') => NO deadlock