Mysql锁的真面目

419 阅读5分钟

Mysql锁分类详情

Mysql表级锁

表级锁介绍

Mysql表级锁由Mysql SQL layer层实现
  • Mysql的表级锁有两种:1.表锁;2.元数据锁(其实就是用来锁表结构的)
  • Mysql查看表级锁定的争用状态变量:show status like 'table%'

  • table_locks_immediate:立刻能够获取到表锁的数量.
  • table_locks_waited:需要等待的表锁树,如果这个数值比较大,说明数据库有性能问题了。

表锁的两种表现形式

  • 表共享读锁(Table Read Lock)

  • 表写锁

Mysql行级锁

行级锁介绍

行级锁由Innodb引擎实现,按照锁定的范围可以分成三种:

  • 记录锁(Record Locks):锁定索引中的一条记录,通过主键指定,where id=2
  • 间隙锁(Gap Locks):锁定记录前,中,后的行,在RR隔离级别下才有。主要为了防止插入间隙内的数据和防止已有数据更新为间隙内的数据。
  • Next-key锁:记录锁+间隙锁

按功能说分成两种:

  • 共享读锁(S):允许一个事务读一行同时阻止其他事务获取相同数据集的排它锁也就是写锁
  • 排他写锁(X):允许获得锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。

写锁的加锁方式

  • 自动添加DML:对于UPDATE,DELETE和INSERT语句,innodb会自动给涉及的数据集加上写锁
  • 手动添加:select * from ...where ..for update

InnoDB的意向锁

Innodb内部也实现了表锁,也就是意向锁,意向锁是mysql内部使用的,不需要用户干预

  • 意向共享锁(IS):事务准备给一个数据集加共享锁前必须先获取该表的IS锁
  • 意向排他锁(IX):事务在给一个数据集加排他锁前必须先获得该表的IX锁

意向锁的作用:意向锁的主要作用是为了在全表更新数据的时候提高mysql的性能。如果没有意向锁,那么在全表更新的时候就需要全表检索某些记录上是否有行锁。

两阶段锁

锁的操作有两个阶段:加锁阶段和解锁阶段。两个阶段不想交,也就是加锁阶段,只加锁,不放锁,解锁阶段,只解锁不加锁。

行锁升级为表锁

我们需要注意mysql加行锁是通过索引加锁的,因此,如果加锁的时候未使用索引,那么行锁就会升级成表锁,因为没有索引需要进行全表扫描。这个情况会严重影响mysql的性能。

Mysql加锁分析

简单Sql的加锁分析

首先,我们先看一条语句:delete from t1 where id=10。 我们要分析这条语句的加锁情况,就需要有几个前提

  • id是不是主键
  • mysql当前的隔离级别是什么
  • id如果不是主键,那么是否有索引 通过这个例子,是为了让大家只,分析锁的前提就是需要知道当前的隔离级别和使用的是什么索引。因为,我们知道是通过索引为数据加锁,因此用了什么索引是很关键的。

我们就以上面的这个语句为例子,为大家分析几种情况:

  • id是主键+RC:这个是最简单的组合,RC隔离级别,只需要在主键上id=10的记录加上X锁即可
  • id是非唯一索引+RC:首先在次要索引(如果不知道什么是次要索引的同学可以参考下,前面讲的索引的相关内容,链接:juejin.cn/post/684490…)中找到符合条件的记录加上X锁,然后拿到主键,在主键索引中找到对应的记录也加上X锁。
  • id无索引+RC:id没有索引,因此会进行全表扫描,因此会对所有的记录都加上X锁

  • id无索引+RR:这种情况不仅会在所有的记录上加X锁,而且会对所有记录加上间隙锁,这种情况下,相当于是加了表锁了。

复杂Sql的加锁分析

要分析复杂sql的加锁情况,首先我们需要先知道SQL中的where条件如何拆分。 所有sql的where条件拆分后可以分成三大类:

  • Index key:用于确定sql在索引中的连续范围的查询条件,因为是一个范围,因此包含起点Index first key和终点Index last key。
    • index first key:用于定位索引的起始范围,只在索引第一次Search path(遍历B+tree找到找到索引正确的位置)时使用。
    • index last key:用来定位索引的终止范围,因而对于起始范围之后读到的每一条索引记录,均需要判断是否已经超过了Index Last Key的范围,若超过,则当前查询结束;
  • Index Filter:用于过滤索引范围内的记录,索引范围中的每一条记录都会与Index Filter进行比较,如果不满足Index filter的条件就会被丢弃,然后继续下一条.
  • Table Filter:过滤不是索引的条件,是where条件的最后一层判断,此时的记录已经满足了Index key和Index filter的条件,并且回表查询了完整的数据,然后判断记录内容是否满足Table Filter的条件,不满足就丢弃,最终剩下的数据就是用户需要的数据,返回给前端用户。

因此,在RR隔离级别下,针对一个复杂的sql,首先要提取where条件。

  • Index key 确定范围,因此要加锁间隙锁;
  • Index Filter:如果Mysql的版本支持ICP(索引下推),则不满足的记录不需要加X锁,否则都需要加X锁;
  • Table Filter:无论是否满足都需要加X锁,在server层过滤。