Skip to content

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隔离级别下都支持
    • 间隙锁的触发条件
      1. 事务隔离级别为可重复读(RR)。
      2. 使用范围查询条件,如 WHERE id > 5。
      3. 等值查询未命中记录,且查询列上存在索引。
      4. 索引为非唯一索引。
    • 间隙锁的加锁规则
      1. 唯一索引的等值查询:如果记录存在,间隙锁退化为行锁。
      2. 唯一索引的范围查询:锁定范围内的所有间隙。
      3. 非唯一索引的查询:锁定范围内的所有间隙,且不会退化为行锁。
      4. 未命中记录的等值查询:锁定最近的左边界和右边界之间的间隙。

TIP

以唯一索引为例

  1. 命中索引锁定一行
  2. 未命中,锁定索引前最近的值和索引后最近的值中间的范围,如果最后没有值则锁定后边全部数据(有临键锁的场景)
  • 临键锁(next-key lock):行锁和间隙锁的组合,同时锁住数据,并锁住数据前面的间隙gap,左开右闭。在RR隔离级别下支持

锁兼容性

参考地址

锁类型共享锁排他锁意向共享锁意向排他锁
共享锁✔️✔️✔️
排他锁
意向共享锁✔️✔️✔️
意向排他锁✔️✔️
  • 共享锁:允许多个事务读取数据,单不允许写入。
  • 排他锁:只允许一个事务进行读取和写入,其他事务只能等待。
  • 意向共享锁:用于表级锁,标识某个事务想要在行级别上施加共享锁。
  • 意向排他锁:用于表级锁,表示某个事务想要在行级别上施加排他锁。