MySQL锁的分类和加锁机制

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 在了解MySQL锁之前,首先我们必须要明白加锁的是为了解决什么问题。我们知道事务具有个隔离性的特性,而隔离性的实现主要就是通过锁以及MVCC机制实现的(关于MVCC机制以及隔离级别的实现可查看文章:MySQL事务详解与隔离级别的实现)。MVCC是一种用来解决读写冲突的无锁并发控制,在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能,解决脏读、幻读、不可重复读等问题。当然只是读取不加锁不阻塞,写操作还是会进行加锁的,即MVCC解决的只是读-写的阻塞问题,写-写依然还是阻塞的。对于写写的并发线程问题,仍需要使用锁来保证线程安全。即MVCC机

在了解MySQL锁之前,首先我们必须要明白加锁的是为了解决什么问题。

我们知道事务具有个隔离性的特性,而隔离性的实现主要就是通过锁以及MVCC机制实现的(关于MVCC机制以及隔离级别的实现可查看文章:MySQL事务详解与隔离级别的实现)。

MVCC是一种用来解决读写冲突的无锁并发控制,在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能,解决脏读、幻读、不可重复读等问题。当然只是读取不加锁不阻塞,写操作还是会进行加锁的,即MVCC解决的只是读-写的阻塞问题,写-写依然还是阻塞的。对于写写的并发线程问题,仍需要使用锁来保证线程安全。即MVCC机制只是为了提高并发性能,减少加锁的情况。

一、锁分类

基于锁的属性分:


共享锁(S锁,MyISAM叫读锁):当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写锁。共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题。

排它锁(X锁,MyISAM叫写锁):当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。排他锁的目的是在数据修改时候,不允许其他人同时修改,也不允许其他人读取,避免了出现脏数据和脏读的问题。

基于锁的粒度分:


表级锁:上锁的时候锁住的是整个表,当下一个事务访问该表的时候,必须等前一个事务释放了锁才能进行对表进行访问;特点:粒度大,加锁简单,容易冲突;


页级锁:介于行级锁和表级锁中间的一种锁。表级锁速度快但冲突多,行级冲突少但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。特点:开销和加锁时间界于表锁和行锁之间,会出现死锁;


行级锁:锁住的是表的某一行或多行记录,其他事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问,特点是粒度小,加锁比较麻烦,但不容易冲突,并发度更高;


记录锁:行锁的一种算法,只不过记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一条记录,加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题;


间隙锁:行锁的一种算法,该锁会锁定一个范围(左开右闭),但是不括记录本身。间隙锁只会出现在REPEATABLE_READ(重复读)的事务级别中;


临键锁:行锁的一种算法,是记录锁和间隙锁的组合,会把查询出来的记录和其左区间锁住


例:如果一个索引有 1, 3, 5, 7 四个值,当等值查询 5 时,临键锁会对( 3,5 ]这个区间进行加锁


基于加锁思想分:


乐观锁(无锁):对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁,只有到数据提交的时候才通过一种机制来验证数据是否存在冲突

悲观锁:对于数据冲突保持一种悲观态度,在修改数据之前把数据锁住,然后再对数据进行读写,在它释放锁之前任何人都不能对其数据进行操作,直到前面一个人把锁释放后下一个人数据加锁才可对数据进行加锁,然后才可以对数据进行操作,一般数据库本身锁的机制都是基于悲观锁的机制实现的

二、不同语句加锁的属性

SELECT … 语句正常情况下为快照读,不加锁;

SELECT … LOCK IN SHARE MODE 语句为当前读,加 S 锁;

SELECT … FOR UPDATE 语句为当前读,加 X 锁;

常见的 DML 语句(如 INSERT、DELETE、UPDATE)为当前读,加 X 锁;

常见的 DDL 语句(如 ALTER、CREATE 等)加表级锁,且这些语句为隐式提交,不能回滚。

三、隔离级别对加锁的影响

MySQL的隔离级别对加锁有影响,不同的隔离级别下,锁粒度是不一样的:


读未提交:修改数据时加记录锁

读提交:修改数据时加记录锁

可重复读:默认加临键锁,但锁可能会发生退化

序列化:读的时候也会加锁

注意以上都是指的走了索引的查询,因为不走索引的查询都是加的表锁,自然不用考虑用的是哪种行级锁算法


读未提交和读提交在写数据时,不管是否范围查询,都只加记录锁


而对于可重复读来说,分为多种情况:


唯一索引等值查询(以1, 4, 7, 10为例)

查询记录存在:退化成记录锁(如查询7则只锁7这一条记录)

查询记录不存在:退化为间隙锁(如查询9则锁住区间(7, 10),因为9不存在,InnoDB先找到7的记录,发现不匹配继续往下找到10大于了查询记录则停止)

唯一索引范围查询:等同于等值查询,存在则加记录锁,不存在则加间隙锁(但要遍历到第一个不满足的记录)

select xxx where id >= 4 and id < 9:这条语句要找的第一行是id=4的记录,本来要加的是(1,4]这个区间的临键锁,因为命中了所以退化为只加4的记录锁,接着不断往后查找第一个不满足的记录,直到找到id=10这条记录,因为id=9是不存在的,所以加了间隙锁(4,10)

非唯一索引等值查询(以1, 4, 7, 10为例)

查询记录存在:左区间加临键锁,有区间加间隙锁(如查询7,则对(4,7]和(7,10)加锁)

查询记录不存在:退化为间隙锁(如查询8则锁住(7,10))

非唯一索引范围查询:不会退化为记录锁或者间隙锁

select xxx where id >= 4 and id < 9:同样的语句,但是如果id是非唯一索引,则id=4仍然加的是临键锁,即(1,4]这个区间同样会被上锁,同样的还有(4,10]这个区间也会被加锁

四、上锁机制

InnoDB采用的是两阶段锁定协议,事务执行过程中,根据需要不断的加锁,最后COMMIT或ROLLBACK的时候一次性释放所有锁

在MySQL中行级锁并不是直接锁记录,而是锁索引

索引分为主键索引和非主键索引两种,如果一条SQL语句操作了主键索引,MySQL就会锁定这条主键索引;如果操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引

如果不通过索引条件检索数据,那么InnoDB将对表中所有数据加锁,等同于表锁。因为没有了索引,查询一条记录就得扫描全表数据,要扫描全表就得锁定表

为什么要两个列都加上锁: 如果只给非主键索引上了锁,那么并发事务通过主键进行其他修改操作,那么此操作并不知道该记录已经被另一个事务操作锁定(因为操作了主键索引的SQL直接查询的是主键索引对应的树)


五、意向锁

如果需要⽤到表锁的话,如何判断表中的记录没有行锁呢,如果一行一行遍历性能则太差。因而采用意向锁来快速判断是否可以对某个表使⽤表锁。


意向锁是表级锁,共有两种:


意向共享锁(Intention Shared Lock,IS 锁):事务有意向对表中的某些加共享锁(S 锁), 加共享锁前必须先取得该表的 IS 锁

意向共享锁与共享锁兼容,与排它锁互斥

意向排他锁(Intention Exclusive Lock,IX 锁):事务有意向对表中的某些记录加排他锁(X 锁),加排他锁之前必须先取得该表的 IX 锁

意向排它锁与共享锁和排它锁互斥

这里指的是表级别的共享锁和排他锁,意向锁不会与行级的共享锁和排他锁互斥


意向锁是有数据引擎自己维护的,用户无法手动操作意向锁,在为数据行加共享 / 排他锁之前, InooDB 会先获取该数据行所在在数据表的对应意向锁。 意向锁之间是互相兼容的。


参考文章:


MySQL死锁系列-常见加锁场景分析 - 孙龙-程序员 - 博客园 (cnblogs.com)


MySQL 四种事务隔离级别 + 锁


MySQL 不同隔离级别,都使用了什么锁?

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
SQL 关系型数据库 MySQL
MySQL 锁
MySQL里常见的几种锁
57 3
|
2月前
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
113 1
|
2月前
|
关系型数据库 MySQL Java
MySQL数据锁:Record Lock,Gap Lock 和 Next-Key Lock
本文基于 MySQL 8.0.30 版本及 InnoDB 引擎,深入解析三种行锁机制:记录锁(Record Lock)、间隙锁(Gap Lock)和临键锁(Next-key Lock)。记录锁锁定索引记录,确保事务唯一修改;间隙锁锁定索引间的间隙,防止新记录插入;临键锁结合两者,锁定范围并记录自身,有效避免幻读现象。通过具体示例展示了不同锁的作用机制及其在并发控制中的应用。
219 2
|
2月前
|
存储 关系型数据库 MySQL
MySQL数据库锁:共享锁和独占锁
本文详细介绍了`InnoDB`存储引擎中的两种行级别锁:共享锁(S锁)与排他锁(X锁)。通过具体示例展示了这两种锁的工作机制及其在`InnoDB`与`MyISAM`引擎中的表现差异。文章还提供了锁的兼容性矩阵,帮助读者更好地理解锁之间的互斥关系。最后总结了两种锁的特点及适用场景。适合希望深入了解`MySQL`并发控制机制的读者阅读。
87 1
|
3月前
|
监控 关系型数据库 MySQL
MySQL锁机制与解决死锁问题
MySQL锁机制与解决死锁问题
336 5
|
2月前
|
存储 关系型数据库 MySQL
MySQL锁,锁的到底是什么?
【10月更文挑战第16天】MySQL 锁锁定的是与数据和资源相关的对象,其目的是为了保证数据的一致性、避免冲突,并在并发环境下合理协调事务或操作的执行。理解锁的对象和意义对于优化数据库性能、处理并发问题至关重要。
78 0
|
2月前
|
关系型数据库 MySQL 数据库
mysql锁详解
通过理解并合理运用MySQL中的锁机制,开发者可以有效管理数据库并发访问,平衡性能与数据一致性需求。更多关于MySQL锁的深入探讨和最佳实践,请参考专业的数据库管理资源[[深入MySQL锁机制详解
56 0
|
3月前
|
关系型数据库 MySQL 数据库
Mysql的锁
本文介绍了MySQL中表级锁和行级锁的区别,其中MyISAM仅支持表级锁,而InnoDB支持表级锁和行级锁,默认为行级锁。表级锁锁定整个表,实现简单,资源消耗少,但并发度低;行级锁仅锁定相关记录,减少冲突,提高并发度,但加锁开销大。此外,还介绍了共享锁和排他锁的概念及意向锁的作用。
|
3月前
|
存储 SQL 关系型数据库
MySQL 的锁机制,那么多的锁,该怎么区分?
MySQL 的锁机制,那么多的锁,该怎么区分?
46 0
|
4月前
|
监控 关系型数据库 MySQL
在Linux中,mysql的innodb如何定位锁问题?
在Linux中,mysql的innodb如何定位锁问题?