MySQL-进阶篇-锁

发布于 2026-06-02 11:18:55 / 17人查看

##锁

###概述

####介绍

锁作为计算机领域用于协调多个进程或线程并发访问某一资源的机制,在数据库系统中具有重要意义。在数据库环境下,除传统计算资源(如CPU、RAM、I/O)的争用外,数据本身也是众多用户共享的资源。确保数据并发访问的一致性与有效性,是所有数据库必须解决的关键问题,而锁冲突更是影响数据库并发访问性能的重要因素。从这一视角来看,锁对于数据库而言不仅尤为重要,而且其应用更为复杂。

###分类

MySQL中的锁,依据锁的粒度可划分为以下三类:

-**全局锁**:对数据库中的所有表实施锁定。

-**表级锁**:每次操作锁定整张表。

-**行级锁**:每次操作锁定对应的行数据。

###全局锁

####介绍

全局锁是对整个数据库实例施加的锁,加锁后整个数据库实例进入只读状态,后续的DML写语句、DDL语句以及涉及更新操作的事务提交语句均会被阻塞。

其典型应用场景为进行全库的逻辑备份,通过对所有表进行锁定,以获取一致性视图,保障数据的完整性。

####演示

说明:绿色代表可执行的操作,红色代表被阻塞的操作。

####特点

在数据库中施加全局锁属于较为重型的操作,存在以下问题:

-若在主库上进行备份,备份期间无法执行更新操作,业务基本处于停滞状态。

-若在从库上进行备份,备份期间从库无法执行主库同步过来的二进制日志(binlog),会导致主从延迟。(运维篇将详细阐述,此处仅作了解)

InnoDB引擎中,备份时可添加参数`–single-transaction`来实现不加锁的一致性数据备份。

```bash

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

```

###表级锁

####介绍

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

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

-**表锁**

-**元数据锁(metadatalock,MDL)**

-**意向锁**

####表锁

表锁可进一步分为两类:

-**表共享读锁(readlock)**

-**表独占写锁(writelock)**

小结:读锁不会对其他客户端的读操作造成阻塞,但会阻塞写操作;写锁则既会阻塞其他客户端的读操作,也会阻塞写操作。

####语法

-加锁:`locktables表名…read/write`。

-释放锁:`unlocktables`/客户端断开连接。

####元数据锁(metadatalock,MDL)

MDL的加锁过程由系统自动控制,无需显式使用,在访问表时会自动添加。MDL锁的主要作用是维护表元数据的数据一致性,当表上存在活动事务时,禁止对元数据进行写入操作,以避免DML与DDL冲突,确保读写的正确性。(元数据可简单理解为表结构;元数据锁可确保当前事务修改表结构时,不存在其他事务对同一张表进行并发操作)

MySQL5.5引入了MDL,对表进行增删改查操作时,添加MDL读锁(共享);对表结构进行变更操作时,添加MDL写锁(排他)。

####查看元数据锁

```sql

selectobject_type,object_schema,object_name,lock_type,lock_durationfromperformance_schema.metadata_locks;

```

####意向锁

为避免DML执行时所加的行锁与表锁发生冲突,InnoDB引入了意向锁,使表锁无需检查每行数据是否加锁,通过使用意向锁减少表锁的检查操作。(避免表锁加锁时逐行检查表的行锁情况)

###分类###

意向共享锁(IS):可通过语句“select…lockinsharemode”添加。

意向排他锁(IX):可由“insert”“update”“delete”“select…forupdate”语句添加。

####意向锁与表锁的兼容情况

意向共享锁(IS):与表锁共享锁(read)兼容,与表锁排他锁(write)互斥。

意向排他锁(IX):与表锁共享锁(read)及排他锁(write)均互斥,且意向锁之间不存在互斥情况。

可通过以下SQL语句查看意向锁及行锁的加锁情况:

```sql

selectobject_schema,object_name,index_name,lock_type,lock_mode,lock_datafromperformance_schema.data_locks;

```

###行级锁

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

InnoDB的数据基于索引组织,行锁通过对索引上的索引项加锁实现,而非对记录直接加锁。行级锁主要分为以下三类:

-行锁(RecordLock):用于锁定单个行记录,防止其他事务对该行进行更新(update)和删除(delete)操作,在RC、RR隔离级别下均支持。

-间隙锁(GapLock):锁定索引记录间隙(不包含该记录),确保索引记录间隙保持不变,防止其他事务在该间隙进行插入(insert)操作,避免产生幻读,在RR隔离级别下支持。

-临键锁(Next-KeyLock):是行锁和间隙锁的组合,同时锁定数据及数据前面的间隙Gap,在RR隔离级别下支持。

####行锁

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

-共享锁(S):允许一个事务读取一行数据,同时阻止其他事务获取相同数据集的排他锁。

-排他锁(X):允许获取排他锁的事务更新数据,同时阻止其他事务获取相同数据集的共享锁和排他锁。

####兼容情况

不同SQL语句所加行锁的类型情况

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

针对唯一索引进行检索时,对已存在的记录进行等值匹配,会自动优化为行锁。

InnoDB的行锁是针对索引加锁,若不通过索引条件检索数据,InnoDB将对表中的所有记录加锁,此时行锁会升级为表锁。

可通过以下SQL语句查看意向锁及行锁的加锁情况:

```sql

selectobject_schema,object_name,index_name,lock_type,lock_mode,lock_datafromperformance_schema.data_locks;

```

###间隙锁/临键锁

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

在索引上进行等值查询(唯一索引)时,对不存在的记录加锁会优化为间隙锁。

在索引上进行等值查询(普通索引),向右遍历时最后一个值不满足查询需求,next-keylock会退化为间隙锁。

在索引上进行范围查询(唯一索引),会访问到不满足条件的第一个值为止。

需注意,间隙锁的唯一目的是防止其他事务插入间隙,且间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙采用间隙锁。