SERIALIZABLE隔离级别下并发执行指定SQL逻辑是否存在问题?
问题背景
隔离级别:SERIALIZABLE
执行逻辑步骤:
select other_col from my_table where pk_col = 1 for update- 若步骤1未返回任何行则跳转至步骤3,否则跳转至步骤5
insert ignore into my_table(pk_col, other_col) values(1, 10)select other_col from my_table where pk_col = 1 for updateupdate my_table set other_col = other_col + 10 where pk_col = 1
用户疑问
当多个事务并发执行上述逻辑时,是否会出现死锁、数据不一致等问题?用户认为每条语句都会获取pk_col=1的排他锁,因此至少不会出现死锁和数据不一致的情况。
分析结果
死锁:确实会发生
在SERIALIZABLE隔离级别下,并发场景下的死锁风险不可忽视:
- 当所有事务执行步骤1时,若
pk_col=1的行不存在,InnoDB会在该主键值对应的间隙上添加间隙锁(Gap Lock)。 - 多个事务持有该间隙锁后,都会进入步骤3执行
insert ignore。插入操作需要获取插入意向锁,但间隙锁与插入意向锁互斥,导致多个事务互相等待对方释放锁资源,最终触发死锁——MySQL会自动选择其中一个事务回滚来解除死锁。
数据一致性:不会出现问题
只要事务能正常完成(死锁回滚后重新执行也算),数据不会出现不一致:
- 不管是
select ... for update、insert ignore还是update,针对pk_col=1的行(或对应间隙)都会持有排他性锁(行锁或间隙锁),确保同一时间只有一个事务能修改该行数据。最终other_col的数值会和事务成功执行的次数完全匹配,不会出现丢失更新等不一致情况。
对用户观点的修正
用户关于数据一致性的判断是正确的,但认为不会出现死锁的结论有误——间隙锁和插入意向锁的冲突是引发死锁的核心原因。
内容的提问来源于stack exchange,提问作者firia2000
相关产品推荐
相关产品推荐

