您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

强人“锁”难,MySQL到底有多少锁?

时间:2020-09-04 17:53:53  来源:  作者:

前言

读锁写锁意向锁,表锁行锁页面锁。

在学习JAVA并发编程的时候,肯定少不了学习。最常见的就是synchronized,锁的概念不是很好理解,有的地方说是锁住了一段代码,有的地方说是锁住了一个对象。弄得初学者都是丈二和尚——摸不着头脑。

抛开这些结论性的说法,说一下我对锁的理解(不管是Java中的锁还是数据库中的锁,还是分布式锁)。当我们需要限制某段程序在同一时刻,最多能被1个线程同时执行的时候就需要锁。这个幸运的线程怎么选出来呢?那就让他们去抢一个许可证吧,重点是需要保证这个许可证是唯一的,一次最多只能被一个线程抢到。许可证不要拘泥于是this,还有可能是数据库设置了唯一键的列、缓存中唯一的key或者一个文件目录。只有抢到了这个许可证的线程,才可以执行这段代码,执行完成或者异常退出后自动释放许可证

理解了这点,再说锁住的是一段代码、一个对象,甚至是一个线程都无所谓了,因为锁的作用就是在某一段时间内将一段代码、一个对象(许可证)、一个线程绑定在一起。

MySQL中的锁与存储引擎有关,MyISAM只支持表级锁,InnoDB既支持表级锁,又支持行级锁

强人“锁”难,MySQL到底有多少锁?

 

InnoDB中的锁

InnoDB实现了行级锁,可以分为两种类型:共享(S)锁定和排他(X)锁定。

  • 共享(S)锁允许持有该锁的事务读取一行,所有又叫读锁
  • 排他(X)锁允许持有该锁的事务更新或删除行,所以又叫写锁

多个事务并发执行时,如果事务T1在某一行r上持有共享(S)锁,那么事务T2的对这行r的锁请求将按以下方式处理:

  • T2对S锁的请求可以立即获得批准。T1和T2都在r上保持了S锁
  • T2对X锁的请求不能获取批准。

如果事务T1在某一行r上拥有排他(X)锁,则事务T2不能获取锁(不论是S锁还是X锁

换言之,S锁和S锁是兼容的,S锁和X锁是冲突的,X锁和X锁是冲突的

强人“锁”难,MySQL到底有多少锁?

 

但是共享锁排它锁并不是指具体的两种锁,而是指两类锁。
同样的乐观锁悲观锁也不是指具体的锁,而是指两类锁。乐观锁是乐观的认为每次都不会发生冲突,只会在更新的时候检查要更新的值有没有被别人修改过,因为没有加锁,所以乐观锁又叫无锁。在数据库中一般是用MVCC实现乐观锁,在Java中用CAS实现乐观锁。至于悲观锁就是悲观的认为每次都会发生冲突,所以每次修改都需要加锁。

表锁

表锁是MySQL中粒度最大的一种锁,简单粗暴的锁住整张表,实现简单所以支持的并发度低。InnoDB和MyIASM都支持表锁,表锁分为共享(S)锁排他(X)锁
表锁的特点是实现简单,并发度低。加锁快,开销小。不会出现死锁。

行锁

行锁是MySQL中粒度最细的一种锁,每次只锁住要操作的那一行。实现复杂,支持的并发度高。只有InnoDB支持行锁。行锁也分为共享(S)锁排他(X)锁。行锁是对索引的锁定。例如SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE,防止任何其他事务插入,更新或删除t.c1值为10的行。行锁始终锁定索引,对于没有创建索引的表,InnoDB创建一个隐藏的聚簇索引并将该索引用于行锁。
行锁的特点是实现复杂,并发度高。加锁慢,开销大。会出现死锁。

意向锁(Intention Locks)

InnoDB支持多种粒度锁定,允许行锁表锁并存。为了使在多个粒度级别上的锁定变得切实可行,InnoDB实现了意图锁意向锁是表级锁,表示事务稍后对表中的行需要上哪种类型的锁(共享锁排他锁)。有两种类型的意图锁:
意向共享锁(IS)表示事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的 IS 锁。
意向排他锁(IX)表示事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的 IX 锁。

SELECT ... LOCK IN SHARE MODE设置IS锁定,而SELECT ... FOR UPDATE设置IX锁定

表级锁之间的兼容性如下

强人“锁”难,MySQL到底有多少锁?

 

有的同学一看到这么多种情况就头晕,死记硬背是不可能死记硬背的,这辈子都不会死记硬背。既然这样,那就干脆不记,花点时间深入了解一下为什么要设计成表中这样。

要想理解这个表,首先得理解为什么要有意向锁(Intention Locks),关于意向锁的作用,官方文档上给出了这么一句话:

Intention locks do not block anything except full table requests (for example, LOCK TABLES … WRITE). The main purpose of intention locks is to show that someone is locking a row, or going to lock a row in the table.

意向锁不会阻止任何其他请求,除了(锁定)全表请求(例如LOCK TABLES ... WRITE)外。意向锁定的主要目的是:声明已经有事务正在锁定表中的行,或者即将锁定表中的行。

这句话透露出了意向锁虽然是表锁,但是和行锁是完全兼容的(包括共享锁排它锁)。但是声明表中的行正在被锁定或者即将被锁定,有什么用呢?

假设事务A给表中某一行加了排它锁,而事务B想给这个表加一个全表的排他锁,这时候事务B就需要判断当前表中到底有没有排他锁,如果有的话,是不能成功加上去表的排它锁的。此时,如果没有意向锁,事务B只能遍历整个索引去判断,这样无疑是低效的。为了解决这个问题,MySQL引入了意向锁。当事务A给某一行加了排它锁或者共享锁后,会分别在表上加意向排它锁(IX)或者意向共享锁(IS),这时,事务B就可很轻松的判断当前表是否有行锁,这也就是前文所说的:为了使在多个粒度级别上的锁定变得切实可行,InnoDB实现了意图锁

理解了意图锁的作用,再来看看上面的表格。S锁和X锁之间的兼容性前文已经理清了,还剩下IX和IS之间以及S/X和IS/IX的兼容性。

由于某一行被加了S锁或者X锁后,表上都会加上对应的IS锁和IX锁。另一个事务想锁住另一条记录,也得加上对应的IS锁或者IX锁,所以IS和IS、IS和IX以及IX和IX必定是兼容的,不然整个表最多只能上一个行锁。

至于S锁、X锁和IS锁、IX锁的兼容性则需与分情况讨论了。当整个表上了X锁之后,再也不能上别的X锁或者S锁了,所以X锁和IS、IX都是冲突的。当整个表上了S锁之后,不能再上X锁了,但是还可以上S锁,所以S锁和IX锁是冲突的,但是和IS锁是兼容的。

这样理解了之后,再看上面的那个表格,似乎也变得有规律了。

间隙锁(Gap Locks)

间隙锁锁定的是索引记录之间的间隙,或者在第一个或最后一个索引记录之前的间隙。例如SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE,可以防止其他事务将t.c1为15的记录插入表中,因为这两个值之间的间隙是被锁定的。
间隙可能跨越单个索引值,多个索引值,甚至为空。
间隙锁的唯一目的是防止其他事务在间隙中插入数据。间隙锁可以共存。一个事务执行的间隙锁,不会阻止另一事务对相同的间隙进行间隙锁定。

Next-Key Locks

Next-Key Locks是索引记录上的行锁索引记录之前的间隙上的间隙锁的组合。如果一个session在索引中的记录R上具有共享排他锁,则另一session不能按照索引顺序在R之前的间隙中插入新的索引记录。
默认情况下,InnoDB设置的事务隔离级别是REPEATABLE READ。在这种情况下,InnoDB使用Next-Key Locks进行搜索和索引扫描,这可以防止幻读(虚读)。关于MySQL隔离级别相关的问题,请参考:面试官:MySQL事务是怎么实现的

插入意图锁(Insert Intention Locks)

插入意图锁是在行插入之前,通过INSERT操作设置的间隙锁的一种类型。如果多个事务想要在同一个间隙中插入不同的值(也就是插入的位置不同),则这多个事务均不会被阻塞。假设有索引记录,其值分别为4和7。单独的事务分别尝试插入值5和6,在获得插入行的排他锁之前,每个事务都使用插入意图锁来锁定4和7之间的间隙,但不会互相阻塞,因为插入的行是无冲突的。

自增锁(AUTO-INC Locks)

AUTO-INC锁是一种特殊的表级锁,由事务插入具有AUTO_INCREMENT列的表中获得。在最简单的情况下,如果一个事务正在向表中插入值,则任何其他事务都必须等待这个事务在该表中进行插入,以便第一个事务插入的行接收连续的主键值。

MyISAM中的锁

相比之下MyISAM中的锁就简单多了,因为MyISAM只支持表锁。并且共享锁排它锁也满足如下关系

强人“锁”难,MySQL到底有多少锁?

 

死锁

前文提到InnoDB行锁可能是出现死锁,死锁是一个计算机领域的概念,而不是数据库特有的,所以死锁的概念是通用的。这里演示下MySQL行锁导致的死锁,这也是官网上给出的例子
首先准备数据

## 创建表
CREATE TABLE t (i INT) ENGINE = InnoDB;
## 新增数据INSERT INTO t (i) VALUES(1);

具体操作的时间线如下

强人“锁”难,MySQL到底有多少锁?

 

事务A在T5执行时,事务B会收到一条错误信息

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

此处发生死锁,因为事务A需要X锁才能删除该行。但是,不能授予该锁定请求,因为事务B已经具有X锁定请求,并且正在等待事务A释放其S锁定。由于B事先要求X锁,因此A持有的S锁也不能升级为X锁。结果,InnoDB为其中一个客户端生成一个错误并释放其锁。此时时,可以授予对另一个客户端的锁定请求,并从表中删除该行。

也就是说MySQL可以自动检测死锁,并且放弃一个事务来成全另一个事务,这点与Java程序中的死锁不一样。

查询事务、锁相关的参考命令如下:

## 查看当前事务状态
select trx_id, trx_state, trx_started, trx_requested_lock_id, trx_wait_started, trx_query, trx_isolation_level from information_schema.innodb_trx;
## 查看当前锁定的事务select * from information_schema.innodb_locks;
## 查看当前正在等待锁的事务select * from information_schema.innodb_lock_waits;

总结

锁是MySQL非常重要的一个部分,虽然一般情况下锁的锁定和释放都由MySQL自动完成。但是了解MySQL中的锁还是很有必要,它让我们进一步的了解了MySQL是如何处理并发的。

作者:Sicimike

原文链接:https://blog.csdn.net/Baisitao_/article/details/104829887



Tags:MySQL   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
前言读锁写锁意向锁,表锁行锁页面锁。在学习Java并发编程的时候,肯定少不了学习锁。最常见的就是synchronized,锁的概念不是很好理解,有的地方说是锁住了一段代码,有的地方说是锁...【详细内容】
2020-09-04  Tags: MySQL   点击:(103)  评论:(0)  加入收藏
1.1 锁概述锁是计算机协调多个进程或线程并发访问某一资源的机制(避免争抢)。在数据库中,除传统的计算资源(如 CPU、RAM、I/O 等)的争用以外,数据也是一种供许多用户共享的资源。...【详细内容】
2020-07-24  Tags: MySQL   点击:(60)  评论:(0)  加入收藏
概述锁是计算机协调多个进程或纯线程并发访问某一资源的机制,这些资源包括CPU、内存、I/O等,而在数据库中,数据也是一种供许多用户(进程/线程)共享的资源。如何保证数据并发访问...【详细内容】
2020-07-08  Tags: MySQL   点击:(48)  评论:(0)  加入收藏
疫情期间在家工作时,同事使用了 insert into on duplicate key update 语句进行插入去重,但是在测试过程中发生了死锁现象:ERROR 1213 (40001): Deadlock found when trying t...【详细内容】
2020-06-17  Tags: MySQL   点击:(81)  评论:(0)  加入收藏
概述很多时候在mysql处理死锁问题时,由于show engine innodb status输出来的死锁日志无任务事务上下文,并不能很好地诊断相关事务所持有的所有锁信息,包括:锁个数、锁类型等。下...【详细内容】
2019-09-27  Tags: MySQL   点击:(317)  评论:(0)  加入收藏
什么是数据库锁数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则。对于任何一种数据库来说都需要有相应的锁定...【详细内容】
2019-09-16  Tags: MySQL   点击:(143)  评论:(0)  加入收藏
锁:计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用外,数据也是一种供许多用户共享的资源。如何保证数据并发的一致性...【详细内容】
2019-09-09  Tags: MySQL   点击:(155)  评论:(0)  加入收藏
▌简易百科推荐
作者:雷文霆 爱可生华东交付服务部 DBA 成员,主要负责Mysql故障处理及相关技术支持。爱好看书,电影。座右铭,每一个不曾起舞的日子,都是对生命的辜负。 本文来源:原创投稿 *爱可生...【详细内容】
2021-12-24  爱可生    Tags:MySQL   点击:(6)  评论:(0)  加入收藏
生成间隙(gap)锁、临键(next-key)锁的前提条件 是在 RR 隔离级别下。有关Mysql记录锁、间隙(gap)锁、临键锁(next-key)锁的一些理论知识之前有写过,详细内容可以看这篇文章...【详细内容】
2021-12-14  python数据分析    Tags:MySQL记录锁   点击:(17)  评论:(0)  加入收藏
binlog 基本认识 MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二...【详细内容】
2021-12-14  linux上的码农    Tags:mysql   点击:(13)  评论:(0)  加入收藏
为查询优化你的查询 大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查...【详细内容】
2021-12-09  元宇宙iwemeta    Tags:mysql   点击:(15)  评论:(0)  加入收藏
测试的目的和原因,公司有很多程序员,每个程序员对数据库和表结构都有自己的理解。而且每个程序员的理解往往是以效率考虑。既然都是为了效率考虑,那么我就来测试一下究竟哪种使...【详细内容】
2021-12-08  吴彬的分享    Tags:Mysql数据库   点击:(14)  评论:(0)  加入收藏
当你们考虑项目并发的时候,我在部署环境,当你们在纠结使用ArrayList还是LinkedArrayList的时候,我还是在部署环境。所以啊,技术不止境,我在部环境。今天这篇文章缕一下在同一台服...【详细内容】
2021-12-08  秃头码哥    Tags:MySQL数据库   点击:(16)  评论:(0)  加入收藏
对于数据分析来说,MySQL使用最多的是查询,比如对数据进行排序、分组、去重、汇总及字符串匹配等,如果查询的数据涉及多个表,还需要要对表进行连接,本文就来说说MySQL中常用的查询...【详细内容】
2021-12-06  笨鸟学数据分析    Tags:MySQL   点击:(19)  评论:(0)  加入收藏
在学习SQL语句之前,首先需要区分几个概念,我们常说的数据库是指数据库软件,例如MySQL、Oracle、SQL Server等,而本文提到的数据库是指数据库软件中的一个个用于存储数据的容器。...【详细内容】
2021-11-24  笨鸟学数据分析    Tags:SQL语句   点击:(23)  评论:(0)  加入收藏
概述以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑。这样的话一份库存数据就有可能同时有多个应用来修改库存数据。比如说,有定时任务域xx.cron,和SystemA域...【详细内容】
2021-11-05  Java云海    Tags:分布式锁   点击:(31)  评论:(0)  加入收藏
MySQL的进阶查询 一、 按关键字排序 使用ORDERBY语句来实现排序排序可针对一个或多个字段ASC:升序,默认排序方式 【升序是从小到大】DESC:降序 【降序是从大到小】ORDER BY的...【详细内容】
2021-11-05  Java热点    Tags:SQL语句   点击:(27)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条