网站建设哈尔滨网站优化4网站开发公司能否挣钱
2026/4/6 6:06:31 网站建设 项目流程
网站建设哈尔滨网站优化4,网站开发公司能否挣钱,软件外包公司如何接单,中国建设银行网站企业前言死锁不是“偶发事故”#xff0c;而是设计问题在实际业务中#xff0c;很多同学第一次接触 MySQL 死锁#xff0c;往往是在日志中看到一句#xff1a;Deadlock found when trying to get lock; try restarting transaction然后的反应通常是#xff1a;“是不是 MySQL …前言死锁不是“偶发事故”而是设计问题在实际业务中很多同学第一次接触 MySQL 死锁往往是在日志中看到一句Deadlock found when trying to get lock; try restarting transaction然后的反应通常是“是不是 MySQL 的 bug”“加索引能不能解决”“把事务拆小一点行不行”事实上死锁不是 MySQL 的 bug而是 InnoDB 锁设计 业务访问模式共同作用的必然结果。本文将从一个非常真实的业务场景出发深入剖析MySQL 在什么情况下会产生死锁InnoDB 各类锁是如何协同工作的为什么SELECT ... FOR UPDATE INSERT特别容易死锁幻读与 Next-Key Lock 在其中扮演了什么角色Online DDL 到底解决了什么问题以及没解决什么一、一个非常典型的业务场景场景描述资源唯一性校验假设有一张表resource业务语义是某个资源只能被创建一次。CREATE TABLE resource ( id BIGINT PRIMARY KEY AUTO_INCREMENT, resource_key VARCHAR(64) NOT NULL, UNIQUE KEY uk_resource_key (resource_key) ) ENGINEInnoDB;常见的业务代码逻辑是BEGIN; SELECT * FROM resource WHERE resource_key A FOR UPDATE; -- 如果不存在 INSERT INTO resource(resource_key) VALUES (A); COMMIT;乍一看这段逻辑非常严谨使用事务使用SELECT FOR UPDATE防止并发插入有唯一索引兜底但在高并发下这正是死锁高发现场。二、InnoDB 锁体系总览先有全局认知在分析死锁之前我们必须先明确 InnoDB 中到底有哪些锁。记录锁Record LockS 型记录锁共享锁多个事务可以同时持有用于普通SELECTX 型记录锁排他锁同一条记录只能有一个事务持有用于UPDATE / DELETE / SELECT FOR UPDATE记录锁只锁已经存在的记录间隙锁Gap Lock锁定的是索引记录之间的“区间”不锁具体记录只锁“范围”用来防止幻读例如索引中存在(10) —— (20)Gap Lock 可以锁住(10, 20)这个区间。Next-Key Lock临键锁InnoDB 中最重要、也是最容易导致死锁的锁记录锁 间隙锁锁定区间(prev_key, current_key]是 InnoDB RR可重复读隔离级别的默认行为SELECT ... FOR UPDATE在索引范围查询下几乎一定会触发 Next-Key Lock。插入意向锁Insert Intention Lock一种特殊的间隙锁是S 型锁用于表示“我想在这个 gap 里插入一条记录”重点插入意向锁与 Gap Lock / Next-Key Lock 是冲突的意向锁Intention Lock表级锁IS / IX表示事务“将要”在某些记录上加锁用于提高锁冲突判断效率不直接参与死锁但几乎所有行锁都会先加意向锁隐式锁 显式锁隐式锁插入时事务尚未真正加行锁但通过事务 ID 隐含保护显式锁当其他事务需要访问这条记录时隐式锁会升级为显式锁隐式锁升级的过程是很多死锁的导火索元数据锁MDL控制表结构的并发访问DDL / DML 之间的互斥是 Online DDL 要重点解决的问题后文详述三、死锁是如何一步一步发生的下面我们用事务 A / 事务 B复盘整个死锁过程。第一步两个事务同时进入事务 A 事务 B BEGIN; BEGIN;第二步SELECT FOR UPDATESELECT * FROM resource WHERE resource_key A FOR UPDATE;假设此时表中还没有resource_key A的记录。会发生什么InnoDB 在唯一索引uk_resource_key上对A所在的索引区间加上X 型 Next-Key Lock锁住的是一个“未来可能插入 A 的区间”结果是事务 A持有 Next-Key LockX 事务 B也尝试加同一个 Next-Key LockX注意Next-Key Lock 是互斥的所以事务 A 成功事务 B 被阻塞等待 A 释放锁第三步事务 A 执行 INSERTINSERT INTO resource(resource_key) VALUES (A);此时发生了一个非常关键的事情插入位置落在已被 Next-Key Lock 锁住的 gapInnoDB 会尝试将插入操作的隐式锁转换为显式锁同时需要获取一个插入意向锁S 型第四步锁冲突出现关键冲突点来了插入意向锁S与事务 B 持有的Next-Key LockX冲突于是事务 A等待 B 释放 Next-Key Lock 事务 B等待 A 释放 Next-Key Lock循环等待成立死锁产生InnoDB 如何处理InnoDB 会通过死锁检测线程选择代价较小的事务回滚抛出死锁异常四、这类死锁的本质原因是什么总结一句话Next-Key Lock 插入意向锁 并发存在性检查 死锁温床更具体地说SELECT FOR UPDATE在 RR 下锁的是“范围”不是“记录”间隙锁之间是兼容的插入时需要插入意向锁插入意向锁与 Next-Key Lock 冲突多事务互相等待形成环五、幻读与 Next-Key Lock 的关系什么是幻读事务 A第一次查询没有记录 事务 B插入一条新记录 事务 A第二次查询发现“多了一条”这就是幻读。InnoDB 如何解决幻读RR 隔离级别下使用Next-Key Lock锁住“可能出现新记录的范围”解决幻读的代价就是更复杂的锁冲突模型六、Online DDL 解决了什么问题传统 DDL 的问题在早期 MySQL 版本中ALTER TABLE resource ADD COLUMN ext VARCHAR(64);会持有排他 MDL 锁阻塞所有SELECTINSERTUPDATEDELETE对线上业务是灾难性的Online DDL 的核心目标Online DDL 的目标不是“无锁”而是最小化 DDL 对 DML 的影响Online DDL 做了哪些事情MDL 锁拆分大部分时间使用共享 MDL只在最终切换阶段使用短暂排他锁拷贝/重建过程异步化后台重建数据前台继续处理读写引入 inplace / instant 算法MySQL 8.0 中大量 DDL 不再重建表Online DDL 能解决死锁吗不能Online DDL 解决的是表结构变更期间的阻塞问题MDL 导致的长时间不可用但它不会改变 InnoDB 行锁模型不会避免 Next-Key Lock不会消除业务逻辑导致的死锁七、如何在业务层面规避这类死锁设计层面避免SELECT ... FOR UPDATE INSERT改为直接 INSERT依赖唯一索引捕获重复键异常降低锁范围精确命中唯一索引避免范围扫描减少 Next-Key Lock 触发概率事务控制事务尽量短不要在事务中做无关操作固定访问顺序减少交叉等待总结为什么会死锁InnoDB 为了解决幻读引入了 Next-Key LockNext-Key Lock 插入意向锁存在天然冲突并发事务在特定业务模式下形成循环等待Online DDL 的定位解决的是DDL 阻塞问题不是行锁死锁的“银弹”一句话结论MySQL 死锁不是偶然而是锁模型与业务访问模式的必然结果理解锁才能真正写出高并发安全的 SQL。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询