2026/1/11 22:59:23
网站建设
项目流程
网站建设的规划书,个人电子邮箱,shopex 网站搬家,营销公司是什么意思MySQL 各种锁机制详解重点放在 InnoDB#xff0c;引擎不同锁语义也不同。
目标#xff1a;弄清楚“有哪些锁、锁什么粒度、什么时候会被加上”。一、为什么需要锁#xff1f;
数据库是“多人同时操作同一份数据”的系统#xff1a;
多个事务并发更新同一行#xff1b;一个…MySQL 各种锁机制详解重点放在 InnoDB引擎不同锁语义也不同。目标弄清楚“有哪些锁、锁什么粒度、什么时候会被加上”。一、为什么需要锁数据库是“多人同时操作同一份数据”的系统多个事务并发更新同一行一个事务在扫一段范围时另一个插入新数据结构变更DDL和读写DML并发执行如果不加锁数据会被“乱改”读到一半被改、更新丢失、约束被破坏。所以需要各种锁控制并发写配合MVCC控制并发读写控制元数据变更DDLMySQL 的锁大致可以从几类角度划分按对象粒度全局锁、库锁、表锁、行锁按功能/用途读锁S、写锁X、意向锁、元数据锁、间隙锁按引擎Server 层锁、InnoDB 锁、MyISAM 锁等。下面重点围绕 InnoDB 来讲。二、从大到小看锁的粒度分类2.1 全局锁Global Lock作用范围整个实例所有数据库、所有表。常见命令FLUSHTABLESWITHREADLOCK;作用把整个实例“锁成只读”常用于全库逻辑备份期间所有 DML、DDL 都会被阻塞写不了。不常用慎用线上大量业务时基本不会直接这么干。2.2 表级锁Table Lock2.2.1 MySQL Server 层的显式表锁语法LOCKTABLESt1READ,t2WRITE;UNLOCKTABLES;特点不区分引擎属于 Server 层机制READ其他会话可读不能写WRITE其他会话不能读也不能写粒度粗并发度差实际业务很少手工用。2.2.2 MyISAM 的表锁MyISAM 没有行锁只有表锁读锁READ LOCK多读互不阻塞写锁WRITE LOCK写独占阻塞其它读写。这也是 MyISAM 不适合高并发写场景的重要原因。2.3 元数据锁Metadata LockMDL作用对象表结构元数据层面自动加不能手动控制。场景对一张表执行SELECT/INSERT/UPDATE/DELETE时获得一个MDL 读锁阻止别人对该表执行结构变更DDL对表执行ALTER TABLE/DROP TABLE等 DDL 时需要获取MDL 写锁会等待所有 MDL 读锁释放。作用保证 DDL 和 DML 不会“打架”比如你在跑查询时不会有人把表给删了。注意长事务会长期持有 MDL 读锁这会导致后续的 DDL 一直阻塞在“Waiting for table metadata lock”线上经常见到这种场景。2.4 行级锁Row Lock——InnoDB 主角InnoDB 提供的行级锁包括记录锁Record Lock间隙锁Gap LockNext-Key Lock记录锁 间隙锁插入意向锁Insert Intention Lock以及上层逻辑上的共享锁S 锁读锁排他锁X 锁写锁意向锁意向共享 / 意向排他行级锁的特点粒度细并发度高成本高于表锁默认是行锁 MVCC组合模式。下面逐个拆。三、InnoDB 行锁的类型3.1 共享锁S和排他锁X逻辑层面最常见的两种共享锁Shared Lock, S 锁多个事务可以同时持有 S 锁通常用于读互相不冲突排他锁Exclusive Lock, X 锁只允许一个事务持有通常用于写和其它 S/X 锁都不兼容除自己。兼容矩阵简化当前持有 \ 请求S 请求X 请求S兼容冲突X冲突冲突常见 SQL-- 共享锁SELECT*FROMtWHEREid1LOCKINSHAREMODE;-- 8.0 之后不推荐用 FOR SHARESELECT*FROMtWHEREid1FORSHARE;-- 排他锁SELECT*FROMtWHEREid1FORUPDATE;3.2 意向锁Intention Lock作用对象表级别但用来配合行锁使用。意向共享锁IS事务打算在某些行上加共享锁意向排他锁IX事务打算在某些行上加排他锁。为什么需要意向锁主要是为了配合表锁如果要给整张表加表级 S/X 锁需要知道表中是否存在行锁冲突不可能一行行扫描所以设计了“意向锁”。行为当事务要在某一行上加 X 锁时会先在表上加 IX 锁当事务要在某一行上加 S 锁时会先在表上加 IS 锁。表级锁与意向锁的兼容大致如下记个直观印象即可ISIXS 表锁X 表锁IS√√√×IX√√××S 表锁√×√×X 表锁××××总结意向锁本身不会阻塞普通行锁它的主要任务是加速“表锁与行锁之间的冲突判断”。3.3 记录锁Record Lock锁定“索引上的某一条记录”本质是锁定某个索引键值。例子SELECT*FROMuserWHEREid10FORUPDATE;假设id有索引就会对id 10这一条索引记录加记录锁X 锁其他事务不能修改或删除这条记录。注意InnoDB 的行锁是基于索引实现的没有索引就可能退化成表锁或锁一大片。3.4 间隙锁Gap Lock锁定“索引之间的间隙”不包括记录本身。比如索引里现有值10, 20, 30, 40则间隙为(-∞,10)、(10,20)、(20,30)、(30,40)、(40,∞)。间隙锁用来阻止其他事务在某些范围“插入新记录”本质目的是防止“幻读Phantom Read”。例子SELECT*FROMtWHEREageBETWEEN20AND30FORUPDATE;InnoDB在某些隔离级别可能会不仅锁定现有的满足条件的记录还会锁定 2030 之间的“间隙”阻止插入新的 age 在这个范围内的数据从而在后续同一事务再次查询时不会出现“多出一条新的行”的幻读。3.5 Next-Key Lock记录锁 间隙锁是“记录锁 间隙锁”的组合锁定一个“左开右闭”的区间(前一个索引值, 当前索引值]。在 InnoDB 默认的REPEATABLE READ下对索引范围查询带 for update / for share会采用 Next-Key Lock它既锁定记录本身也锁定附近的间隙减少幻读发生的可能。简单理解Next-Key Lock 将记录锁扩展到一个范围以防止新记录插进来造成幻读。3.6 插入意向锁Insert Intention Lock一种特殊的间隙锁用于插入时当事务要在某个间隙插入记录时会先声明一个“插入意向锁”多个事务在不同位置插入彼此不会互相阻塞只有插入位置冲突时才会等待。四、InnoDB 锁是如何被加上的4.1 普通 SELECT不加锁SELECT*FROMtWHEREid10;默认是一致性读Consistent Read利用 MVCC 读取数据版本一般不加行锁除非特殊情况如手工 hint 或特定隔离级别。4.2 锁定读SELECT … FOR UPDATE / FOR SHARE-- 排他锁SELECT*FROMtWHEREid10FORUPDATE;-- 共享锁SELECT*FROMtWHEREid10FORSHARE;特点在可重复读 / 读已提交下都会对符合条件的记录加行锁记录锁/Next-Key Lock会参与锁冲突判定用于做“先查后改”的场景防止并发脏写。4.3 UPDATE / DELETE 自动加锁UPDATEtSETbalancebalance-100WHEREid1;DELETEFROMtWHEREid2;InnoDB 自动对匹配的记录加排他锁行锁其他事务不能修改这些行直到事务提交/回滚。五、锁与索引的关系一个非常重要的点行锁是基于索引的。如果 WHERE 条件能用到索引只锁命中的那几行如果没用上索引可能退化为锁住更多记录甚至全表。例子-- id 上有索引SELECT*FROMuserWHEREid10FORUPDATE;-- ✅ 只锁 id 10 对应的那条索引记录-- name 上无索引SELECT*FROMuserWHEREnameTomFORUPDATE;-- ❌ 可能会锁更大范围扫描整个表行锁挨个加甚至接近表锁效果优化建议对经常锁定某个字段的场景要确保该字段有索引避免在没有合适索引的条件上使用 FOR UPDATE / FOR SHARE。六、MySQL 锁相关的典型问题6.1 死锁Deadlock典型死锁场景事务 A锁记录 1 - 再锁记录 2 事务 B锁记录 2 - 再锁记录 1两边互相等对方释放锁形成死锁。InnoDB 会自动检测死锁回滚其中一个事务报错Deadlock found when trying to get lock。避免方案访问多行时尽量按照固定顺序加锁控制事务粒度和时间避免大事务理解你的索引和锁范围。6.2 锁等待如果锁冲突但不是死锁就会出现等待超过innodb_lock_wait_timeout默认 50s后报错。排查手段SHOWENGINEINNODBSTATUS\G;或在新版本里用performance_schema里的锁视图。七、锁与隔离级别的关系简要在不同隔离级别下读未提交大量读直接读最新版本几乎不加锁但允许脏读读已提交读时只看到已提交事务的最新版本通常不加间隙锁可重复读默认使用MVCC保证同一事务内多次读取一致加上Next-Key Lock / 间隙锁避免/减少幻读串行化很多读都会退化为锁定读强制串行执行锁竞争最激烈。简化理解隔离级别越高加的锁越多或锁得越久并发性能越差但数据越“安全”。八、常见锁类型速查表锁类型粒度作用对象主要用途全局锁实例所有库表全库备份阻止写入表锁表整张表简单并发控制MyISAM、多数不用元数据锁 MDL表表结构 / 元数据DDL 与 DML 并发安全行锁记录锁行单条记录索引项控制并发更新单行间隙锁行索引间隙防止插入避免幻读Next-Key Lock行记录 间隙InnoDB 默认可重复读的主要锁插入意向锁行插入位置多事务在不同位置插入时协调S 锁行/表共享读允许多读不允许写X 锁行/表排他写写时独占阻塞其它读写意向锁 IS/IX表声明将要在行上加 S/X 锁加速表锁与行锁冲突检测九、小结MySQL 锁分层很多全局锁、表锁、MDL、行锁等等。InnoDB 的并发控制核心是行锁 间隙锁 Next-Key Lock MVCC。行锁基于索引实现没索引容易锁更多数据甚至锁全表。锁的细粒度在带来高并发能力的同时也带来了死锁、锁等待等问题需要通过合理设计索引控制事务范围和顺序使用EXPLAIN、SHOW ENGINE INNODB STATUS等工具来排查。真正摸清楚锁的行为一般要结合隔离级别 索引结构 实际 SQL反复实验和看执行计划。这篇可以当成“概念地图”后面你如果有具体 SQL我可以帮你一起分析“加了哪些锁、锁到了哪一段”。