MySQL的锁

64 阅读3分钟

MySQL锁的分类?(根据加锁的范围)

  • 全局锁
  • 表级锁
    • 表锁
    • 元数据锁(MDL)
    • 意向锁
    • Auto-Inc
  • 行级锁
    • 记录锁(Record Lock)
    • 间隙锁(Gap Lock)
    • 临键锁(Next-Key Lock)

对MySQL锁的分析

全局锁:主要用于全库逻辑备份

# 执行全局锁
flush tables with read lock
# 释放全局锁
unlock tables

表锁

  • 表级别的共享锁,就是读锁
  • 表级别的独占锁,就是写锁
# 读锁
lock tables users read;
# 写锁
lock tables users write;
# 释放锁
unlock tables

当我们对一个表加读锁时,本线程只能读,不能写;其它线程也只能读,不能写

元数据锁(MDL):当我们对这个数据库表操作时,会自动给这个表加MDL锁

  • 对一张表进行增删改查时,加的是MDL读锁
  • 对表结构变更时,加的是MDL写锁

MDL是为了保证当用户对表进行CRUD时,防止其它线程对这个表结构进行修改

MDL是在事务提交后,才会释放

意向锁:目的是为了快速判断是否有记录被加锁

  • 意向独占锁和意向共享锁都是表级锁,不会与行级的共享锁和独占锁发生冲突
  • 意向锁之间也不会发生冲突
  • 意向锁只会和共享表锁和独占表锁发生冲突
# 先在表上加上意向共享锁,然后读取的记录加共享锁
select ... lock in share mode;
# 先在表上加上意向独占锁,然后对读取的记录加独占锁
select ... for update;

Auto-Inc锁:是一个特殊的表锁机制

  • 在插入数据时,可以不指定主键的值,数据库会自动给主键赋递增的值
  • 锁的释放:不是在一个事务提交后释放,而是在执行完插入语句后,立即释放锁
  • 一个事务在持有Auto-Inc锁的过程中,其它事务如果向该表插入数据时,会被阻塞
    • 从而保证插入数据时,被Auto_Increment 修饰的字段的值,是连续递增的

Record Lock:称为记录锁,锁住的是一条记录

但是记录锁是有S锁和X锁之分的:

  • 当一个事务对一条记录加了 S 型记录锁后,其他事务也可以继续对该记录加 S 型记录锁,但是不可以对该记录加 X 型记录锁
  • 当一个事务对一条记录加了 X 型记录锁后,其他事务既不可以对该记录加 S 型记录锁,也不可以对该记录加 X 型记录锁

记录锁

Gap Lock:称为间隙锁,只存在于可重复读隔离级别

  • 目的是为了解决可重复读隔离级别下的幻读现象
  • 间隙锁之间是兼容的

Next-Key Lock:临键锁,是记录锁和间隙锁的组合,锁定一个范围,并且锁定记录本身

  • 临键锁是 前开 后闭 的区间,即 (]
  • 同时临键锁也满足记录锁X和S锁之间的兼容性

所以临键锁即能保存记录,又能阻止其它事务将新记录插入到被保护的前面的间隙中

这里为大家拓展一个插入意向锁

插入意向锁

业务场景:一个事务在插入一条记录的时候,需要判断插入的位置是否被其他事务加了临键锁。如果有临键锁,插入操作就会发生阻塞,直到拥有间隙锁的那个事务提交为止,在此期间,会生成一个插入意向锁,表明有事务想在某个区间插入新纪录,但是现在处于等待状态

插入意向锁:虽然名字有意向锁,但是并不是意向锁,它是一种特殊的间隙锁,属于行级别锁