一、概述
或许您跟我一样,被MySQL各种各样的锁晃得眼花缭乱,接下来本文将对9种锁进行简单的分析,让读者对MySQL锁的整体框架有个清晰的认识。
- 全局锁
- 表级锁
- 表锁
- 元数据锁(MDL)
- 意向锁(intention lock)
- 自增锁(AUTO-INC)
- 行级锁
- 行锁
- 间隙锁
- 临键锁 next-key lock
- 插入意向锁
二、正文
1、全局锁
- 定义:全局锁就是对整个数据库实例加锁
- 作用:让整个库进入只读状态,DML和DDL的增删改都会被阻塞
- 命令:
- 上锁:flush tables with read lock;
- 释放锁:unlock tables;或者连接断开的时候也会自动释放锁
- 应用:不支持事务的引擎如myisam,可以用全局锁做全库逻辑备份
2、表锁
- 定义:对整张表上锁,不依赖于储存引擎(不管是MySQL的什么存储引擎,对于表锁的策略都是一样的)
- 作用:对整个表上锁,分为读锁(共享锁、S锁)和写锁(排他锁、X锁)
- 命令:
- 上锁:lock tables 表名 read / write (读 / 写锁)
- 释放锁:unlock tables;
3、元数据锁(MDL)
- 定义:元数据即表结构,属于数据库隐式上锁(自动上锁),执行DML的时候上MDL读锁,执行DDL上MDL写锁
- 作用:保证DDL和DML直接有序进行,保证读写正确性
4、意向锁(intention lock)
- 定义:表明当前事务对表里面的行加锁的意向,上行锁之前就会上意向锁(自动上锁),分为意向排他锁(IX)和意向共享锁(IS),如果该行锁是读锁,则对应的意向锁就是IS,反之是IX
- 作用:当一个事务想加表锁的时候,势必要确保表里面每一行都没有排他行锁(不管是共享表锁和排他表锁,都和排他行锁冲突),要对表的所有行进行遍历检查,如果数据量很大,则效率非常低。于是innodb推出意向锁,用以表示表是否存在行锁,提高表锁的效率。当表存在IX,则代表有某一行上了排他锁,那么将暂时无法上表锁
- 加锁规则:
- 在事务可以获取表中行的共享锁之前,它必须首先获取表上的 IS 锁
- 在事务可以获取表中行的排他锁之前,它必须首先获取表上的 IX 锁
- 备注:意向锁之间不会冲突,虽然它是表级锁,因为它表明的是行锁的意图。表锁和意向锁可能会冲突,只有共享表锁和IS能兼容,其他情况都会冲突
5、自增锁(AUTO-INC)
- 定义:自增锁是一种特殊的表级别锁,专门针对事务插入AUTO_INCREMENT类型的列。最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。
6、行锁
- 定义:锁住某一行的索引可以是普通索引,也可以是主键索引,分为写锁(X)和读锁(S)。读读兼容,读写冲突,写写冲突。
- 作用:保证并发安全,粒度是某行数据
- 命令:
- 上锁:SELECT ... LOCK IN SHARE MODE(S)、普通查询语句(S)、SELECT ... FOR UPDATE(X)、UPDATE或DELETE或INSERT语句 (X)
- 释放锁:事务结束
- 备注:为什么给某行上了X锁之后,其他事务仍然能查询此行数据:因为MVCC一致性读,不同事务根据trx_id进行比较可以读到相应的数据版本
7、间隙锁
- 定义:锁住索引之间的间隙,左开右开的区间,如(4,7)
- 作用:在RR隔离级别下防止幻读出现(即锁住间隙,防止插入造成幻读)
- 作用范围:大部分情况只在RR生效,在RC情况下在外键场景下会涉及
- 互斥情况:同一间隙的间隙锁不互斥,但是会排斥往间隙insert的操作
- 命令:
- 上锁:上行锁的时候一起上
- 释放锁:事务结束
8、临键锁 (next-key lock)
- 定义:临键锁=记录锁+间隙锁,左开右闭区间,比如(4,7]
- 作用:实际上,在RR隔离级别,我们通常说的加行锁,加的就是临键锁,但是有些情况临键锁会退化为间隙锁
- 命令:
- 上锁:上行锁的时候一起上
- 释放锁:事务结束
9、插入意向锁
- 定义:插入意向锁是一种在 INSERT 操作之前设置的一种间隙锁,插入意向锁表示了一种插入意图
- 作用:当多个不同的事务,同时往同一个索引的同一个间隙中插入数据的时候,它们互相之间无需等待,即不会阻塞(要是单纯按照之前间隙锁的理论,必须要等一个间隙锁释放了,下一个事务才可以往相同的间隙处插入数据)
- 命令:
- 上锁:insert语句
- 释放锁:事务结束