MySQL锁
锁类型
表锁
- 表共享读锁(Table Read Lock)
- 表独占写锁(Table Write Lock)
行锁
- 共享锁(S Lock)
- 排他锁(X Lock)
- 意向锁(IS Lock)
- 意向排他锁(IX Lock)
- 自增锁(AUTO-INC Lock)
- 外键锁(Foreign Key Lock)
页锁
- 页共享读锁(Page Read Lock)
- 页独占写锁(Page Write Lock)
锁粒度
- 全局锁:锁定数据库中所有表。加上全局锁之后,整个数据库只能允许读,不允许做任务写操作
- 表级锁:每次操作锁住整张表。分三类
- 表锁(分为表共享读锁read lock、表独占写锁write lock)
- 元数据锁(meta data lock,MDL):基于表的元数据加锁,加锁后整张表不允许其他事物操作。这里的原数据可以理解为一张表的表结构
- 意向锁(分为意向共享锁、意向排它锁):这个是InnoDB中为了支持多粒度的锁,为了兼容行锁、表锁而设计,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查
- 行级锁:没次操作锁住对应的行数据。分三类
- 记录锁/Record锁:也就是行锁、一条记录和一行数据是同一个意思。防止其他事物对此进行uodate和delete,在RC、RR隔离级别下都支持
- 间隙锁/Gap锁:锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事物在这个间隙进行insert,产生幻读。在RR隔离级别下都支持
- 临建锁/Next-Key锁:间隙锁的升级版,同时具备记录锁+间隙锁的功能,在RR隔离级别下都支持
以互斥性的角度划分
- 共享锁/S锁:不同事物之间不会互相排斥、可以同时获取的锁
- 排它锁/X锁:不同事物之间相互排斥、同时只能允许一个事物获取的锁
- 共享排他锁/SX锁:MySQL5.7版本中新引入的锁,主要是解决SMO带来的问题
以操作类型的纬度划分
- 读锁:查询数据时使用的锁
- 写锁:执行插入、删除、修改、DDL语句时使用的锁
以思想的纬度划分
- 乐观锁:每次执行前认为自己会成功,因此先尝试执行,失败时再获取锁
- 悲观锁:每次执行前都认为自己无法成功,因此会先获取锁,然后行再执行
共享锁(S锁)加锁方式
SQL
select * from xxxx LOCK in SHARE MODE;
-- mysql8
select * from xxxx FOR SHARE;排他锁(X锁)加锁方式
sql
-- mysql8
select * from xxxx for update;全局锁加锁方式
sql
flush tables with read lock;
unlock tables;表共享读锁
sql
lock tables xxxx read;
-- 其他写操作不能进行
-- 解锁
unlock tables;表独享写锁
sql
-- 加锁
lock tables xxxx write;
-- 解锁
unlock tables;| 对应sql | 锁类型 | 说明 |
|---|---|---|
| lock tables xxx read/write(表锁) | SHERED_READ_ONLY / SHARED_NO_READ_WRITE | |
| select、select .... lock in share mode(普通读、共享锁) | SHARED_READ(元数据共享锁) | 与SHARED_READ、SHARED_WRITE兼容,与EXCKUSIVE互斥 |
| insert、update、delete、select ... for update(增、改、删、排它锁) | SHARED_WRITE(元数据共享锁) | 与SHARED_READ、SHARED_WRITE兼容,与EXCLUSIVE互斥 |
| alter table ... (修改表结构) | EXCLUSIVE(元数据排它锁) | 与其他MDL都互斥 |
意向锁
- 意向共享锁(LS):由语句select...lock in share mode添加,与表锁共享锁(read)兼容,与表锁排他锁(write)互斥。在准备给表数据添加一个S锁时,需要先获得表的LS锁
- 意向排他锁(LX):由insert、update、delete、select...for update添加。与表锁共享锁(read)及排他锁(write)都互斥,意向锁之间不会互斥。在准备给表数据添加一个X锁时,需要先获得该表的LX锁
INFO
事务一旦提交,意向共享锁、意向排他锁,都会自动释放
行级锁(行锁实现算法)
- 行锁(record lock)(记录锁):锁定单个行记录的锁,防止其他事务对此行进行update和delete。在RC、RR隔离级别下都支持
- 针对索引记录(index record)的锁定
- 间隙锁(gap lock):锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻度。在RR隔离级别下都支持
- 间隙锁的触发条件
- 事务隔离级别为可重复读(RR)。
- 使用范围查询条件,如 WHERE id > 5。
- 等值查询未命中记录,且查询列上存在索引。
- 索引为非唯一索引。
- 间隙锁的加锁规则
- 唯一索引的等值查询:如果记录存在,间隙锁退化为行锁。
- 唯一索引的范围查询:锁定范围内的所有间隙。
- 非唯一索引的查询:锁定范围内的所有间隙,且不会退化为行锁。
- 未命中记录的等值查询:锁定最近的左边界和右边界之间的间隙。
- 间隙锁的触发条件
TIP
以唯一索引为例
- 命中索引锁定一行
- 未命中,锁定索引前最近的值和索引后最近的值中间的范围,如果最后没有值则锁定后边全部数据(有临键锁的场景)
- 临键锁(next-key lock):行锁和间隙锁的组合,同时锁住数据,并锁住数据前面的间隙gap,左开右闭。在RR隔离级别下支持
锁兼容性
| 锁类型 | 共享锁 | 排他锁 | 意向共享锁 | 意向排他锁 |
|---|---|---|---|---|
| 共享锁 | ✔️ | ❌ | ✔️ | ✔️ |
| 排他锁 | ❌ | ❌ | ❌ | ❌ |
| 意向共享锁 | ✔️ | ❌ | ✔️ | ✔️ |
| 意向排他锁 | ✔️ | ❌ | ✔️ | ❌ |
- 共享锁:允许多个事务读取数据,单不允许写入。
- 排他锁:只允许一个事务进行读取和写入,其他事务只能等待。
- 意向共享锁:用于表级锁,标识某个事务想要在行级别上施加共享锁。
- 意向排他锁:用于表级锁,表示某个事务想要在行级别上施加排他锁。