MySQL 常见死锁场景-- 并发插入相同主键场景

具体而言,当一个事务执行删除操作时,会执行 row_update_for_mysql,进而获取记录的 X record lock。插入操作同样会获取 X record lock,大部分情况下,初始会获取隐式锁,随后在检测冲突时,才会转换为 X lock。在分析死锁案例时,我们关注事务在记录上的锁状态。当事务1回滚后,事务2/3获得了记录...
MySQL 常见死锁场景-- 并发插入相同主键场景
在探讨 MySQL 的常见死锁场景时,本文聚焦于并发插入相同主键这一特定情况。主键的唯一性验证与二级索引 unique key 导致的死锁有着相似之处。主键的唯一性判断发生在 row_ins_clust_index_entry_low,通过一个条件判断:如果当前 index 为 unique index,且 cursor 找到的记录与插入的记录相同,则需执行 row_ins_duplicate_error_in_clust。

对于普通的 INSERT 操作,检查 primary key 唯一时,会加 S record lock;对于 REPLACE INTO 或者 INSERT ON DUPLICATE 操作,则加 X record lock。当两个事务尝试在主键上操作同一记录,且其中一个是唯一性检查,另一个是修改操作时,死锁问题便可能出现。

具体而言,当一个事务执行删除操作时,会执行 row_update_for_mysql,进而获取记录的 X record lock。插入操作同样会获取 X record lock,大部分情况下,初始会获取隐式锁,随后在检测冲突时,才会转换为 X lock。

在分析死锁案例时,我们关注事务在记录上的锁状态。当事务1回滚后,事务2/3获得了记录的 S lock,并在插入操作提交时发现死锁。死锁信息显示,事务1尝试获取记录的 X insert intention lock,而事务2持有 S next-key lock,与事务1的 X insert intention lock产生冲突。死锁的原因在于,事务等待在记录的下一个记录上的 S lock。

对于锁的升级问题,主要出现在两种场景:当两个事务同时等待在同一个记录上时,其中一个事务持有锁,另一个事务在执行操作时升级锁状态。例如,在插入操作时,如果记录已被标记为删除,且删除标记未从 B-tree 中物理删除,那么插入操作会升级为在下一个记录上的 GAP lock。因此,两个事务同时尝试获取 X record lock,最终在对方持有的 GAP S lock 上卡住。

在另一个案例中,通过在 session1 执行 commit 后,观察到 session2/3 获得了记录 2 上的 s lock。然而,当 session1 进行 commit 时,发现死锁。这与前一个案例的不同之处在于,删除操作是标记删除而非物理删除,因此记录仍在 B-tree 中,使得插入操作也试图获取记录 2 的 s lock。由于删除标记的存在,插入操作实际上变成修改操作,因此需要获取 X record lock,进而与 session2/3 持有的 s lock 产生冲突。

总结而言,主键的唯一性验证和并发插入相同主键的场景都可能导致死锁。理解和识别这些操作在并发环境下的锁交互是解决死锁问题的关键。通过监控和分析事务在执行过程中的锁状态,可以帮助识别和预防潜在的死锁情况。2024-09-29
mengvlog 阅读 9 次 更新于 2025-06-20 01:04:36 我来答关注问题0
檬味博客在线解答立即免费咨询

mySQL相关话题

Copyright © 2023 WWW.MENGVLOG.COM - 檬味博客
返回顶部