MySql

MySql进阶(五)——锁&事务原理

Nick · 2月28日 · 2026年 · 本文4928字 · 阅读13分钟227

锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源(CPU、RAM、I/0)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。

MySQL中的锁,按照锁的粒度分,分为一下三类:

  1. 全局锁:锁定数据库中的所有表。
  2. 表级锁:每次操作锁住整张表。
  3. 行级锁:每次操作锁住对应的行数据。

全局锁

全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将被阻塞。

其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。

基本操作:
使用全局锁:flush tables with read lock
释放全局锁:unlock tables

演示图:
MySql进阶(五)——锁&事务原理-Nickの博客

特点:

数据库中加全局锁,是一个比较重的操作,存在以下问题:

  1. 如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆。
  2. 如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟。(该结构会在后续主从复制讲解)
    解决方法:

在InnoDB引擎中,我们可以在备份时加上参数 –single-transaction 参数来完成不加锁的一致性数据备份。

mysqldump --single-transaction -uroot -p123456 itcast > itcast.sql

(只适用于支持「可重复读隔离级别的事务」的存储引擎)

原理补充:通过加上这个参数,确保了在备份开始时创建一个一致性的快照,通过启动一个新的事务来实现这一点。(该事务的隔离级别是Repeatable Read级别),从而实现在该事务读取下一直读取的是创建时的数据,而不影响其他事务的读写操作。

表级锁

每次操作锁住整张表。锁定粒度大,发生锁的冲突的概率最高,并发度最低。应用在MyISAM、InnoDB、BDB等存储引擎中。

对于表级锁,主要分为一下三类:

  1. 表锁
  2. 元数据锁(meta data lock,MDL)
  3. 意向锁

表锁

对于表锁,分为两类:

表共享读锁(read lock)
表独占写锁(write lock)

读锁不会阻塞其他客户端的读,但是会阻塞写。写锁既会阻塞其他客户端的读,又会阻塞其他客户端的写。

语法:

//表级别的共享锁,也就是读锁;
//允许当前会话读取被锁定的表,但阻止其他会话对这些表进行写操作。
lock tebles t_student read;

//表级锁的独占锁,也是写锁;
//允许当前会话对表进行读写操作,但阻止其他会话对这些表进行任何操作(读或写)。
lock tables t_stuent write;

释放所有锁:

unlock tables (会话退出,也会释放所有锁)

元数据锁

MDL加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据的数据一致性,在表
上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性。

  • 对一张表进行 CRUD 操作时,加的是 MDL 读锁;
  • 对一张表做结构变更操作的时候,加的是 MDL 写锁;

MySql进阶(五)——锁&事务原理-Nickの博客

查看元数据锁:

select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema.metadata_locks;

意向锁

为了避免DML在执行时,加的行锁与表锁的冲突,在InnoDB中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查。

意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁(lock tables … read)和独占表锁(lock tables … write)发生冲突

如果没有「意向锁」,那么加「独占表锁」时,就需要遍历表里所有记录,查看是否有记录存在独占锁,这样效率会很慢。

那么有了「意向锁」,由于在对记录加独占锁前,先会加上表级别的意向独占锁,那么在加「独占表锁」时,直接查该表是否有意向独占锁,如果有就意味着表里已经有记录被加了独占锁,这样就不用去遍历表里的记录。

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

加锁方式:
意向共享锁:(先在表上加上意向共享锁,然后对读取的记录加共享锁)
由 select ... lock in share mode 添加

意向独占锁:(先表上加上意向独占锁,然后对读取的记录加独占锁)
由 insert、update、delete、select ... for update 添加

行级锁

行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB存储引擎中。

  1. 行锁(Record Lock):锁定单个行记录的锁,防止其他事务对此行进行update和delete。在RC、RR隔离级别下都支持。
  2. 间隙锁(GapLock):锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读。在RR隔离级别下都支持。
  3. 临键锁(Next-Key Lock):行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。在RR隔离级别下支持。

Record Lock(行锁)

Record Lock 称为记录锁,锁住的是一条记录。而且记录锁是有 S 锁和 X 锁之分。

InnoDB实现了以下两种类型的行锁:

  • 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。
  • 排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。
    MySql进阶(五)——锁&事务原理-Nickの博客

行锁类型:
MySql进阶(五)——锁&事务原理-Nickの博客

默认情况下,InnoDB在 REPEATABLE READ事务隔离级别运行,InnoDB使用 next-key锁进行搜索和索引扫描,以防止幻读。

注意:

  1. 针对唯一索引进行检索时,对已存在的记录进行等值匹配时,将会自动优化为行锁。
  2. InnoDB的行锁是针对于索引加的锁,不通过索引条件检索数据,那么!nnoDB将对表中的所有记录加锁,此时 就会升级为表锁

查看意向锁及行锁的加锁情况:

select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from peformance_schema.data_locks;

Gap Lock(间隙锁)

MySql进阶(五)——锁&事务原理-Nickの博客

Next-Key Lock(临键锁)

MySql进阶(五)——锁&事务原理-Nickの博客

默认情况下,InnODB在 REPEATABLE READ事务隔离级别运行,InnoDB使用 next-key 锁进行搜索和索引扫描,以防止幻读。

  1. 索引上的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁 。
  2. 索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,next-keylock退化为间隙锁。
  3. 索引上的范围查询(唯一索引)–会访问到不满足条件的第一个值为止。

InnoDB引擎

逻辑存储结构

MySql进阶(五)——锁&事务原理-Nickの博客
MySql进阶(五)——锁&事务原理-Nickの博客

架构

MySql进阶(五)——锁&事务原理-Nickの博客

内存架构

MySql进阶(五)——锁&事务原理-Nickの博客
MySql进阶(五)——锁&事务原理-Nickの博客
MySql进阶(五)——锁&事务原理-Nickの博客
MySql进阶(五)——锁&事务原理-Nickの博客

磁盘结构

MySql进阶(五)——锁&事务原理-Nickの博客
MySql进阶(五)——锁&事务原理-Nickの博客

后台线程

MySql进阶(五)——锁&事务原理-Nickの博客

事务原理

事务:
事务 是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。

特征:

  • 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
  • 一致性(Consistency) :事务完成时,必须使所有的数据都保持一致状态。
  • 隔离性(lsolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
  • 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。

特性原理分类图:
MySql进阶(五)——锁&事务原理-Nickの博客

redo log

重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。

该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复使用。

Buffer Pool在产生脏页数据的时候,会先将数据存储到 redo log buffer 再存储到 redo log 中进行磁盘持久化存储,在内存出现异常(比如突然断电)时,通过redo log中持久化的数据进行回滚。过程如下图:
MySql进阶(五)——锁&事务原理-Nickの博客

redo log 要写到磁盘,数据也要写磁盘,为什么要多此一举?
写入 redo log 的方式使用了追加操作,所以磁盘操作是顺序写,而写入数据需要先找到写入位置,然后才写到磁盘,所以磁盘操作是随机写。

undo log

回滚日志,用于记录数据被修改前的信息,作用包含两个:提供回滚 和 MVCC(多版本并发控制)。

undo log 和 redo log 记录物理日志不一样,它是逻辑日志。可以认为当 delete 一条记录时,undo log中会记录一条对应的insert记录,反之亦然,当 update 一条记录时,它记录一条对应相反的 update 记录。当执行 rollback 时,就可以从 undo log 中的逻辑记录读取到相应的内容并进行回滚。

undo log 销毁:undo log 在事务执行时产生,事务提交时,并不会立即删除undol0g,因为这些日志可能还用于 MVCC。

undo log 存储:undo log 采用段的方式进行管理和记录,存放在前面介绍的 rollback segment 回滚段中,内部包含1024个 undo log segment.

MVCC

当前读:
读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select…lock in share mode(共享锁),select… for update、update、insert、delete(排他锁)都是一种当前读。

快照读:
简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。

  • Read committed:每次select,都生成一个快照读。
  • Repeatable Read:开启事务后第一个select语句才是快照读的地方。
  • Serializable:快照读会退化为当前读。

MVCC:
全称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MVSOL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、read View。

三个隐藏字段
MySql进阶(五)——锁&事务原理-Nickの博客

undo log
回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。
当insert的时候,产生的undoloq日志只在回滚时需要,在事务提交后,可被立即删除。
而update、delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。

那么何时删除?

事务提交后:
对于INSERT操作,事务提交后,undo log可以被立即删除,因为不再需要用于回滚。
对于UPDATE和DELETE操作,undo log不会立即被删除,因为它们可能在后续的快照读取中被使用。

快照读取结束:
当所有依赖于该undo log的快照读取操作结束后,undo log才会被删除。这意味着如果有一个事务正在进行快照读取,并且依赖于某个undo log,那么这个undo log会一直保留直到该事务结束。
MySql进阶(五)——锁&事务原理-Nickの博客

readview
ReadView(读视图)是 快照读 SOL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。

ReadView中包含了四个核心字段:
MySql进阶(五)——锁&事务原理-Nickの博客
MySql进阶(五)——锁&事务原理-Nickの博客
MySql进阶(五)——锁&事务原理-Nickの博客
依次比较 undo log 日志中版本数据链,找到可以进行访问的版本数据。

MySQL管理

系统数据库介绍

Mysql数据库安装完成后,自带了一下四个数据库,具体作用如下:

MySql进阶(五)——锁&事务原理-Nickの博客

常用工具

mysql

MySql进阶(五)——锁&事务原理-Nickの博客

mysqladmin

MySql进阶(五)——锁&事务原理-Nickの博客

mysqlbinlog

MySql进阶(五)——锁&事务原理-Nickの博客

mysqlshow

MySql进阶(五)——锁&事务原理-Nickの博客

mysqldump

MySql进阶(五)——锁&事务原理-Nickの博客

mysqlimport/source

MySql进阶(五)——锁&事务原理-Nickの博客

0 条回应
在线人数:1人 来访统计
新时代
Ado
隐藏