MySQL锁篇-锁类型

发布于:2025-09-06 ⋅ 阅读:(14) ⋅ 点赞:(0)

锁类型

MySQL的锁主要根据加锁范围进行分类,分为 全局锁、表级锁、行级锁

全局锁

flush tables with read lock

执行后整个库都处在只读状态,数据库的写删更操作以及表结构变更操作都阻塞

unlock tables

又或者本次会话断开,全局锁自动释放

全局锁最主要的使用场景就是做全库的逻辑备份,避免备份时候数据被变更,导致备份和实际数据不一致的情况。

不过由于全局锁期间服务无法进行写删更操作,在真实项目场景上完全无法被接受,尤其是在互联网场景,数据量和并发都比较高,完全无法支持数据库短时间只能读这种情况。

为了避免这种情况,Innodb引擎通过可重复读的隔离级别来实现这种逻辑备份,备份数据库的时候开启事务创建RV,事务执行期间使用RV的快照数据,基于MVCC的支持保证备份期间业务能对数据正常操作

备份数据量太大会不会对服务带来影响?
会的,备份长事务本身通常不会直接导致MySQL崩溃,主要风险是Undo Log膨胀和资源竞争。

  1. 由于要保证事务期间资源一直访问旧数据,因此这部分数据在Undo Log中无法清除。在高并发写的事务场景下,会导致Undo Log日志一直上升最终磁盘空间不足
  2. IO压力,备份本身会带来巨大IO流量和Buffer Pool空间,而其他业务操作也在使用,这些资源竞争会拖慢业务的请求响应

解决方案 要避免上诉问题,简单的做法是物理拷贝

逻辑备份的话,在凌晨等低流量时间操作备份减少对业务的影响,以及监控磁盘和锁等资源的使用情况

表级锁

  • 表锁
  • 元数据锁 MDL
  • 意向锁
  • AUTO-INC 锁

表锁

表锁分为共享锁和独占锁

共享锁(读锁)下,所有会话都能读当前表,但都不能写当前表;加锁会话自己也不能读写其他表,直到解锁。

独占锁是写锁,本线程能读写,其他线程不能读写

元数据锁

MDL锁是对表进行操作的时候自动加的,保证用户对表做CRUD的时候,其他线程对表结构进行修改

eg 我在对a表做crud的时候,自动对表加上MDL读锁,如果其他线程要修改表结构就要申请MDL写锁,但是写锁需要读锁释放后才能加,也就是说,需要crud执行完才能修改表结构。反之亦然。

这里会出现一个问题

MDL的释放是在事务提交后,假设线程A执行一个长事务,先加上MDL读锁,线程C此时修改表结构,申请MDL写锁申请不到,阻塞住,此时后续对这个表的全部select操作都会阻塞。

why 申请MDL锁底层是有一个优先队列,队列中写锁优先级比读锁高,出现MDL写锁等待,会阻塞该表全部crud操作(因为写锁优先级高,后面来的读锁都只能在写锁后面等待写锁释放)

[ 已授予: 读锁 A, 读锁 B ]

→ 写锁 C(排队,优先级高)

→ 读锁 D(后到的读锁,只能排在写锁后面)

→ 读锁 E …

意向锁

意向锁的目的是为了快速判断表里是否有记录被加锁。主要是为了解决表级锁和行级锁之间进行快速冲突判断。避免引擎执行遍历操作

场景:事务A在给第x行加上x行锁前,事务A先给这张表IX锁。

事务 B 想加 表级 X 锁(LOCK TABLES ... WRITE 或 DDL)

  • 它不需要去遍历 1~N 行;
  • 一看表头上已经有 IX,就知道“表里某行正被独占”;
  • 直接拒绝/等待成本 O(1)

总结意向锁是表级“提示位”:表里有没有行被锁?有→堵在门口;没有→放行
它让表锁与行锁冲突检测从“逐行翻抽屉”变成“看门口指示灯”,常数时间完成

AUTO-INC锁

锁插入的操作,主要是保证主键自增。触发时机为插入操作,释放时机为插入操作执行结束

这种会导致大量插入操作情况在性能被影响,以及可能产生阻塞。

MySQL后期版本中提供一种更轻量级的锁来实现

通过在字段值上加锁并实现完自增后释放,来提高性能

行级锁

Innodb引擎支持,MyISAM引擎不支持

行级锁分三类 记录锁 间隙锁 两者组合的锁

记录锁

记录锁是针对单条记录做锁定的

记录锁分为S锁和X锁

S锁本质上就是共享锁,X锁是独占锁

间隙锁

间隙锁是锁住范围的锁,存在目的是为了解决可重复读隔离级别下出现的幻读问题

互斥锁最核心的操作就是锁住区间内的记录阻止一切想要插入其中的数据,保证不会出现幻读的情况

Next-Key Lock

前两种的结合,锁住间隙锁和记录锁的数据

并且存在锁互斥关系,这里和间隙锁不太一样,间隙锁是兼容多个锁锁在同一个范围的,但是记录锁是不支持的,因此 Next-Key Lock也不支持

插入意向锁

事务A在a点插入数据的时候,如果插入位置被其他事务B加了间隙锁,那么会在a点尝试加插入意向锁并阻塞当前事务A,直到事务B完成

这种锁如果发送长事务的情况,没有什么解决方案,只能kill长事务或者代码设计之处去避免长事务


网站公告

今日签到

点亮在社区的每一天
去签到