Mysql中的锁(理论篇)

这篇具有很好参考价值的文章主要介绍了Mysql中的锁(理论篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

MVCC机制遗留的问题

为什么在可重复读级别下,幻读没有产生?
回想一下在事务隔离级别那篇文章中,可串行化是通过什么保证的?
对操作的每一行记录加读锁、写锁和范围锁;任何其他事务都必须等待持有锁的事务释放锁之后才能进行操作;
而可重复读级别相比之下唯一少的就是范围锁,所以无论你是否了解过具体原因,都应该去猜测推理,大概率是加了范围锁。而在这里,他有一个特殊的名字,叫做间隙锁。
虽然我很想直接上间隙锁相关的内容,但是为了更加有体系化,最好还是完整梳理一下;
本篇文章最好是有一点基础再看,因为本身就是自记录,没有打算写一篇完整的教学博客。

读锁和写锁(共享锁和排它锁)

Shared Lock 共享锁(S锁),也叫读锁;不和读锁冲突,但和写锁冲突;
当事务A持有读锁的时候,事务B依然可以加读锁;但是除了事务A自己可以加写锁,其他事务都无法对这条记录加写锁。
Exclusive Lock 排他锁(X锁),也叫写锁;和谁都冲突;
即当事务A持有记录的写锁时,其他事务读锁和写锁都加不了

S X
S 兼容 冲突
X 冲突 冲突

行和列代表不同事务

表锁

上锁和解锁

lock tables 表名 [as alisa] 锁类型;
unlock tables ;

表锁的命令就是上述两行,且表锁也分读写锁,表级读写的兼容冲突和读写锁一致。
通过lock tables 命令加锁的session,在释放锁之前,能且只能执行lock tables 命令后面指定的表,命令类型和锁类型保持一致;比如 lock tables A read,那么后面就只能读A表,而不能执行读B表,或者写A表;如下面的例子一样;另外如果使用了别名,那么需要确保查询语句涉及的别名和lock table的别名完全一致;

lock tables simple read;
select * from simple;
select * from batch_insert;
//[HY000][1100] Table 'batch_insert' was not locked with LOCK TABLES
update simple set name=3 where id=2;
Table 'simple' was locked with a READ lock and can't be updated

Unlock tables 会显式的释放所有该session之前加的所有表;另一个作用是释放FLUSH TABLES WITH READ LOCK命令所加的全局读锁;

Another use for UNLOCK TABLES is to release the global read lock acquired with the FLUSH TABLES WITH READ LOCK statement, which enables you to lock all tables in all databases. See Section 13.7.8.3, “FLUSH Statement”.

lock tables、start transcation命令可以隐式的释放之前持有的锁;
查看锁情况
可通过下面的命令查看表是否上锁,name_locked为0表示上锁
show OPEN TABLES where In_use > 0;
Mysql中的锁(理论篇)

WRITE locks normally have higher priority than READ locks to ensure that updates are processed as soon as possible. This means that if one session obtains a READ lock and then another session requests a WRITE lock, subsequent READ lock requests wait until the session that requested the WRITE lock has obtained the lock and released it.

对于读-写-读的情况,由于锁的优先级较高,如果申请写的session迟迟获取不到锁,会阻塞后续其他session申请读锁;具体分析看Case1;

全局读锁

关于全局锁,我一共只在两篇文档中看到过;一个是《Mysql45讲》的06篇,一个mysql官方文档的lock-table文章和FLUSH Statement文章,所以了解的并不全,加上此时的我还不太关心数据库主从的问题,所以也没有深入研究。
FLUSH TABLES WITH READ LOCK

Closes all open tables and locks all tables for all databases with a global read lock.

元数据锁

Statements acquire metadata locks one by one, not simultaneously, and perform deadlock detection in the process.
DML statements normally acquire locks in the order in which tables are mentioned in the statement.
DDL statements, LOCK TABLES, and other similar statements try to reduce the number of possible deadlocks between concurrent DDL statements by acquiring locks on explicitly named tables in name order.

元数据锁是一个个获取的,DML和DDL通过不同的方式定义执行的顺序;官网提供了一个rename table的顺序例子,但那个例子挺迷的;
//可以通过这个表查看元数据锁的情况
select * from performance_schema.metadata_locks;

To ensure transaction serializability, the server must not permit one session to perform a data definition language (DDL) statement on a table that is used in an uncompleted explicitly or implicitly started transaction in another session. The server achieves this by acquiring metadata locks on tables used within a transaction and deferring release of those locks until the transaction ends. A metadata lock on a table prevents changes to the table's structure. This locking approach has the implication that a table that is being used by a transaction within one session cannot be used in DDL statements by other sessions until the transaction ends.

如果一个session或者一个事务持有某个表的元数据锁,那么另一个session或者事务就无法执行DDL操作;
https://dev.mysql.com/doc/refman/8.0/en/metadata-locking.html

读写阻塞问题

关于元数据锁,在《Mysql45讲》中有提到一个问题,后加的读锁会被前面的写锁所阻塞,很类似于表锁最后提到的优先级问题,有没有可能是一个原因呢?具体见case2

行锁(Record Lock)

A record lock is a lock on an index record.

行锁是在索引上的一个锁。这句话非常重要!
这里的索引可以是聚簇索引也可以是二级索引,如果表中没有索引或者查询的条件没有索引,又或者优化器认为索引没有作用,这个时候就会退化为“表锁”,但我总感觉像是锁定了所有行。
另外,如果表中没有定义聚簇索引,会自动生成一个隐藏的索引。

间隙锁(Gap Lock)

A gap lock is a lock on a gap between index records, or a lock on the gap before the first or after the last index record.

单靠行锁是无法解决幻读的问题的,所以innodb引入了间隙锁的概念,只在RR级别生效。间隙锁是一个范围锁,比如所以索引1和索引3之间就存在(1,3)这样一个间隙,当这个间隙被锁定的时候,就无法插入值为2的记录。
不同的事务对于同一个间隙加锁是允许发生的,因为都是在保护这个间隙不被插入数据。

Gap locking is not needed for statements that lock rows using a unique index to search for a unique row.

当查询条件是唯一索引,如果查询的值存在且是唯一的一行记录,那么是不需要加间隙锁的;因为间隙锁的出现就是为了防止幻读,对于加了唯一索引的表,同样的查询条件永远只能查出唯一的一条,既然已经保证了唯一,那么就没有间隙锁的必要了。
那如果查询结果不存在?以及查询条件是范围查询?又或者是普通索引甚至没有索引呢?
关于这些情况的排列组合,见case3..

临键锁(next-key Lock)

A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.

临建锁=行锁+间隙锁,是innodb RR级别默认加的锁;由于锁定的是当前索引记录行和索引前的部分,所以一般总结为左开右闭;
假如存在索引10,11,13,20,那么就会存在以下几个区间,最后一个范围是mysql会假定一个非常大的supremum,但由于实际并不存在这个值,所以是左开右开。
(negative infinity, 10]
(10, 11]
(11, 13]
(13, 20]
(20, positive infinity)

意向锁

表意向锁

innodb支持多粒度锁,即允许行锁和表锁同时存在,并且在加锁的时候需要进行冲突检测;
比如事务A已经持有了a表的一条记录索引的行锁,这个时候B事务想要给a表加表锁,就需要一行行查看是否存在行锁;为了优化这种情况,innodb引入了意向锁的概念。
表意向锁是个表级锁,分为读意向锁(IS)和写意向锁(IX),它们添加的时机是在对行索引添加S锁和X锁之前;即如果想要对某一行加锁,就必须先取得这个表的意向锁。这样当另一个事务需要判断时,就不需要一行行进行检查,只需要查看这个表是否具有意向锁即可。
意向锁的作用主要是用来阻塞表锁的。所以其互相之间是不存在互斥的,只和表锁存在冲突,即读写冲突,具体就像是下面表格这样;
暂时无法在飞书文档外展示此内容

插入意向锁

An insert intention lock is a type of gap lock set by INSERT operations prior to row insertion. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap. Suppose that there are index records with values of 4 and 7. Separate transactions that attempt to insert values of 5 and 6, respectively, each lock the gap between 4 and 7 with insert intention locks prior to obtaining the exclusive lock on the inserted row, but do not block each other because the rows are nonconflicting.

插入意向锁是间隙锁类型的一种意向锁,锁的是间隙;是在进行插入之前必须申请获得的锁,所以和间隙锁是冲突的;换句话说,如果你想插入一条语句,那么这个语句对应的间隙必须不存在锁,这样你才能加上插入意向锁,进而插入数据;
而且,插入意向锁只要插入的不是同一行,那么就可以同时插入;

自增锁(AUTO-INC Locks)

An AUTO-INC lock is a special table-level lock taken by transactions inserting into tables with AUTO_INCREMENT columns.

如官方文档所说,自增锁其实是只针对于自增的字段,算是一个表级锁,一般对我们来说就是自增主键;当有多个事务同时想要插入,由于自增的值必须保持连续,所以多个事务的插入必须串行;

参考文档:

https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-shared-exclusive-locks
https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html
06 | 全局锁和表锁 :给表加个字段怎么有这么多阻碍?-极客时间
mysql MDL读写锁阻塞,以及online ddl造成的“插队”现象_花落的速度的博客-CSDN博客
MYSQL查看表是否被锁、以及解锁_mysql查看锁表_清石小猿的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-514481.html

到了这里,关于Mysql中的锁(理论篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • epoll准备就绪列表保护机制,引发的锁问题讨论

    epoll 就绪队列应该使用什么数据结构?为什么? 在 Nginx 中,就绪队列通常使用链表来实现。具体来说,就绪队列是一个双向链表,其中每个节点都包含了一个 ngx_event_t 结构体,用于表示一个已经准备就绪的事件。当 epoll 检测到某个文件描述符上有 I/O 事件发生时,就会将相应

    2023年04月13日
    浏览(38)
  • 【MySQL】MySQL中的锁

    全局锁是对整个数据库实例加锁,整个库处于只读状态。 适用场景 全局锁适用于做全库逻辑备份,但是整个库处于只读状态,在备份期间,所有的更新操作、DDL将会被阻塞,会对业务产生影响。 single-transaction mysqldump备份时可以使用–single-transaction参数,在备份数据之前启动

    2024年02月05日
    浏览(37)
  • MySQL中的锁(表锁、行锁)

    锁是计算机协调多个进程或纯线程并发访问某一资源的机制。在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所在有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性

    2024年02月09日
    浏览(46)
  • Git企业开发控制理论和实操-从入门到深入(一)|为什么需要Git|Git的安装

    那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助。 高质量博客汇总 https://blog.csdn.net/yu_cblog/category_12379430.html 然后就是博主最近最花信息的一个专栏《Git企业开

    2024年02月11日
    浏览(46)
  • MYSQL中的锁(面试难点重点)

    首先说一下 这个加锁是个啥子过程呢 我们拿一条记录举例,这个记录就放在这,没人操作它,他就没生成锁结构, 直到有个事务操作它了,然后给它才生成了个锁结构,锁结构两个参数 trx(生成该锁的事务) is_waiting(正在等待就是:true 没在等待就是 false) (锁里面很多参数 这里这

    2024年02月16日
    浏览(45)
  • Mysql中的锁(case篇)

    上篇文档中提到过 WRITE locks normally have higher priority than READ locks to ensure that updates are processed as soon as possible. This means that if one session obtains a READ lock and then another session requests a WRITE lock, subsequent READ lock requests wait until the session that requested the WRITE lock has obtained the lock and released it

    2024年02月11日
    浏览(34)
  • 为什么WebSocket需要前端心跳检测,有没有原生的检测机制?

    本文代码 github、gitee、npm 在web应用中,WebSocket是很常用的技术。通过浏览器的WebSocket构造函数就可以建立一个WebSocket连接。但当需要应用在具体项目中时,几乎都会进行心跳检测。 设置心跳检测,一是让通讯双方确认对方依旧活跃,二是浏览器端及时检测当前网络线路可用

    2024年02月03日
    浏览(58)
  • 面试官:Tomcat 为什么要破坏 Java 双亲委派机制?被问傻眼了。。。

    来源:www.jianshu.com/p /abf6fd4531e7 我想,在研究tomcat 类加载之前,我们复习一下或者说巩固一下java 默认的类加载器。楼主以前对类加载也是懵懵懂懂,借此机会,也好好复习一下。 楼主翻开了神书《深入理解Java虚拟机》第二版,p227, 关于类加载器的部分。请看: 代码编译的

    2024年02月10日
    浏览(40)
  • 【人工智能】为什么说大语言模型能力遵循规模理论 Scaling Law(即模型能力随着训练计算量增加而提升) ?

    目录 为什么说大语言模型能力遵循规模理论 Scaling Law(即模型能力随着训练计算量增加而提升) ?

    2024年03月25日
    浏览(69)
  • 警惕看不见的重试机制:为什么使用RPC必须考虑幂等性

    在RPC场景中因为重试或者没有实现幂等机制而导致的重复数据问题,必须引起大家重视,有可能会造成例如一次购买创建多笔订单,一条通知信息被发送多次等问题,这是技术人员必须面对和解决的问题。 有人可能会说:当调用失败时程序并没有显示重试,为什么还会产生重

    2024年02月06日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包