MYSQL中的锁(面试难点重点)

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

首先说一下 这个加锁是个啥子过程呢

我们拿一条记录举例,这个记录就放在这,没人操作它,他就没生成锁结构, 直到有个事务操作它了,然后给它才生成了个锁结构,锁结构两个参数 trx(生成该锁的事务) is_waiting(正在等待就是:true 没在等待就是 false) (锁里面很多参数 这里这是为了方便理解例举了两个),然后下一个事务试图操作这条记录,就会发现本记录已经加上锁了,就要再生成一个锁(本次锁的 等待状态就是:true)

举个例子

有个记录 我们称为 record

然后事务A 对record进行操作 事务开始 record加了一个锁 参数  trx:A  is_waiting:false

然后来了个byd事务B 又想对record进行操作 事务开始 发现 哎?这有个锁了 然后它也生成一个锁

锁参数 trx:B  is_waiting:true   is_waiting:true就代表它正在等待 事务B就停在这里了 直到变成false才能继续执行

然后事务A提交 释放锁 然后事务B获得锁 参数变成trx:B  is_waiting:false 

表级锁

S锁

共享锁(英语原文是share什么玩意 反正S是share 查了一下是Share Locks)  共享锁就是咋的呢 一个事务A对此表加了个S锁 然后又来个事务B试图加了个S锁 这次不会像正常流程一样阻塞 而是会加锁成功 此条记录同时有两个锁(都是is_waiting:false的)

X锁

独占锁(Exclusive Locks) 与其他锁冲突(包括S锁) 

这里就得具体描述了

事务A加了个 X锁 事务B加了个S锁 会阻塞

事务A加了个 S锁  事务B加了个X锁 会阻塞 懂了吧 就是不管X锁先加后加 都会阻塞

事务A加了个 X锁  事务B加了个X锁 阻塞

事务A加了个S锁 事务B加了个S锁 不阻塞 

MYSQL中的锁(面试难点重点),mysql,面试,java

IS锁:意向共享锁 

IX锁:意向独占锁

这里是啥意思呢 就是说我们的表级锁和行级锁之间也是冲突的 就比如我们行级加了一个X锁

这时我们想在表上加一个X锁 会阻塞 但是我们怎么去看这个表里面有没有行级X锁吗 遍历每条记录吗 那老MYSQL一整几百万条记录 遍历累死

所以提出了 意向锁 IS锁就是说明当前表内有S锁 IX锁就是说明当前表内有X锁

那么这个阻塞的问题呢

IX锁和IX锁冲不冲突? 不冲突 我不同记录加了X锁 这个表也被加入了多次IX锁

那IX和IS锁呢? 也不冲突 不同记录加了X锁 S锁 表上加了IX IS 可以

那X和IX呢? (这里X指表级的)  冲突 IX就说明当前表内有X锁了 而X表级锁和行级锁冲突 (可以把表级锁当做 所有记录都加了行锁呢)

同理 S和IX X和IS....

MYSQL中的锁(面试难点重点),mysql,面试,java

AUTO-INC锁

眼熟不?像不像某个字段(AUTO_INCREMENT 自增列) 

我们在插入记录的时候 自增列是不需要我们自己指定值的 那么如果多个事务同时插入的时候

就会乱套 所以MYSQL提供了两种解决方法

1.AUTO-INC锁:行插入语句时就在表级别加一个 AUTO-INC 锁,然后为每条待插入记录的 AUTO_INCREMENT 修饰的列分配递增的值,在该语句执行结束后,再把 AUTO-INC 锁释放掉。这样一个事务在持有 AUTO-INC 锁的过程中,其他事务的插入语句都要被阻塞,可以保证一个语句中分配的递增值是连续的。

2.轻量级锁 如果因为一列就阻塞所有插入操作未免有点太耽误时间了 所以就提出了个这么个玩意

在为插入语句生成 AUTO_INCREMENT 修饰的列的值时获取一下这个轻量级锁,然后生成本次插入语句需要用到的 AUTO_INCREMENT 列的值之后,就把该轻量级锁释放掉,并不需要等到整个插入语句执行完才释放锁。

如果我们的插入语句在执行前就可以确定具体要插入多少条记录,比方说我们上边举的关于表 t 的例子中,在语句执行前就可以确定要插入2条记录,那么一般采用轻量级锁的方式对 AUTO_INCREMENT 修饰的列进行赋值。这种方式可以避免锁定表,可以提升插入性能。

对吧对吧 提前知道插入多少记录了 就可以提前准备了

可以通过innodb_autoinc_lock_mode的系统变量来控制到底使用上述两种方式中的哪种来为AUTO_INCREMENT修饰的列进行赋值,当innodb_autoinc_lock_mode值为0时,一律采用AUTO-INC锁;当innodb_autoinc_lock_mode值为2时,一律采用轻量级锁;当innodb_autoinc_lock_mode值为1时,两种方式混着来(也就是在插入记录数量确定时采用轻量级锁,不确定时使用AUTO-INC锁)。不过当innodb_autoinc_lock_mode值为2时,可能会造成不同事务中的插入语句为AUTO_INCREMENT修饰的列生成的值是交叉的,在有主从复制的场景是不安全的.(性能的代价)

顺便说下:表级的X锁 S锁基本用不上 锁住全表实在太重了 耽误事 对应的IX IS锁也不常用

行级锁

重点来了啊重点来了

记录锁(Record Locks)

记录锁分x锁和s锁不多赘述

间隙锁(Gap Locks)

锁如其名 锁住间隙的

假如说有 1  2  3  4这几条记录在 记录3上加间隙锁就是  锁住了2和3之间的间隙 让其他事务无法在这个间隙上面加记录  假如说有一条记录来了 想在2和3之间插入 看一眼它后面的记录 我超!!!!锁!!!!

额 然后就阻塞了

这个 gap锁 的提出仅仅是为了防止插入幻影记录而提出的,虽然有 共享gap锁 和 独占gap锁 这样的说法,但是它们起到的作用都是相同的。而且如果你对一条记录加了 gap锁 (不论是 共享gap锁 还是 独占gap锁 ),并不会限制其他事务对这条记录加 正经记录锁 或者继续加 gap锁 ,再强调一遍, gap锁 的作用仅仅是为了防止插入幻影记录的而已。

啊 你会不会想 那我要是想在最后一条记录前那个卵间隙加记录 那么我缺失的这个锁这一块谁来给我补呢?

每个数据页中有 两个伪记录

Infimum 记录,表示该页面中最小的记录。Supremum 记录,表示该页面中最大的记录。

假如说我在那个(4,正无穷)的这个间隙上面加锁 就直接在这个Supremum 记录就可以了

Next-Key Locks 

我又想锁住记录 又想锁住记录前面的间隙 就使用Next-Key Locks吧!

Next-key Locks本质上等于俩锁  记录锁+间隙锁

Insert Intention Locks

插入意向锁 当一条记录想插入这个间隙的时候 发现这个位置被间隙锁锁住了 于是它在这个时候开始等待 等待的过程生成一个插入意向锁 表示有记录想在这个间隙里面插入记录 但是还在等待

插入意向锁是一种特殊的间隙锁

有个事务A对这个间隙加锁了 然后来了一个事务B 事务C想在这个间隙里面加记录 B C来一看 好嘛

这有个间隙锁 然后他俩生成了插入意向锁 is_wait是false  然后A的间隙锁释放后,他俩就可以获得到插入意向锁(实质上只是is_waiting调整成了true) B和C之间也不会阻塞 可以同时获取到锁 所以有啥用呢

只有当被间隙锁阻塞的时候才会生成插入意向锁

隐式锁

我们前边说一个事务在执行 INSERT 操作时,如果即将插入的 间隙 已经被其他事务加了 gap锁 ,那么本次INSERT 操作会阻塞,并且当前事务会在该间隙上加一个 插入意向锁 ,否则一般情况下 INSERT 操作是不加锁的。那如果一个事务首先插入了一条记录(此时并没有与该记录关联的锁结构)

如果此时对它进行读操作(可以看下面的部分)  SELECT ... LOCK IN SHARE MODE 语句读取这条事务,也就是在要获取这条记录的 S锁 ,或者使用 SELECT ... FOR UPDATE 语句读取这条事务或者直接修改这条记录,也就是要获取这条记录的 X锁,阁下如果不生成任何锁应对的话 就可能产生脏读

立即修改这条记录,也就是要获取这条记录的 X锁 ,该咋办?如果允许这种情况的发生,那么可能产生 脏写 问题。

我们分两种情况讨论解决方案

对于聚簇索引记录来说,有一个 trx_id 隐藏列,该隐藏列记录着最后改动该记录的 事务id 。那么如果在当前事务中新插入一条聚簇索引记录后,该记录的 trx_id 隐藏列代表的的就是当前事务的事务id ,如果其他事务此时想对该记录添加 S锁 或者 X锁 时,首先会看一下该记录的 trx_id 隐藏列代表的事务是否是当前的活跃事务,如果是的话,就代表着有一个插入操作正在进行 ,那么就帮助当前事务创建一个 X锁 (也就是为当前事务创建一个锁结构, is_waiting 属性是 false ),然后自己进入等待状态(也就是为自己也创建一个锁结构, is_waiting 属性是 true )

先发现锁冲突 然后再加锁 所以是隐式锁

对于二级索引记录来说,本身并没有 trx_id 隐藏列,但是在二级索引页面的 Page Header 部分有一个 PAGE_MAX_TRX_ID 属性,该属性代表对该页面做改动的最大的 事务id ,如果PAGE_MAX_TRX_ID 属性值小于当前最小的活跃 事务id ,那么说明对该页面做修改的事务都已经提交了,(如果当前事务正在活跃 那么这个PAGE_MAX_TRX_ID 属性值要么等于这个修改事务 要么是比这个修改事务的id更大 说明后面又新来了一个修改操作 而比它还小 只能说明修改操作都已经提交了)否则就需要在页面中定位到对应的二级索引记录,然后回表找到它对应的聚簇索引记录,然后再重复 情景一 的做法。

Insert的隐式锁

当事务需要加锁的时,如果这个锁不可能发生冲突,InnoDB会跳过加锁环节,这种机制称为隐式锁。隐式锁是 InnoDB 实现的一种延迟加锁机制,其特点是只有在可能发生冲突时才加锁,从而减少了锁的数量,提高了系统整体性能。

隐式锁就是在 Insert 过程中不加锁,只有在特殊情况下,才会将隐式锁转换为显示锁,这里我们列举两个场景。

  • 如果记录之间加有间隙锁,为了避免幻读,此时是不能插入记录的;
  • 如果 Insert 的记录和已有记录存在唯一键冲突,此时也不能插入记录;

 间隙锁情况

每插入一条新记录,都需要看一下待插入记录的下一条记录上是否已经被加了间隙锁,如果已加间隙锁,此时会生成一个插入意向锁,然后锁的状态设置为等待状态(PS:MySQL 加锁时,是先生成锁结构,然后设置锁的状态,如果锁状态是等待状态,并不是意味着事务成功获取到了锁,只有当锁状态为正常状态时,才代表事务成功获取到了锁),现象就是 Insert 语句会被阻塞。

 索引重复

如果在插入新记录时,插入了一个与「已有的记录的主键或者唯一二级索引列值相同」的记录(不过可以有多条记录的唯一二级索引列的值同时为NULL,这里不考虑这种情况),此时插入就会失败,然后对于这条记录加上了 S 型的锁

  • 如果主键索引重复,插入新记录的事务会给已存在的主键值重复的聚簇索引记录添加 S 型记录锁

  • 如果唯一二级索引重复,插入新记录的事务都会给已存在的二级索引列值重复的二级索引记录添加 S 型 next-key 锁

总之就是先发现冲突然后再加锁 如果没有冲突就不加锁 (比喻就是有一个隐形的锁 一旦碰到冲突才会显现出来)

 读时的锁操作

我们前边说在采用 加锁 方式解决 脏读 、 不可重复读 、 幻读 这些问题时,读取一条记录时需要获取一下该记录的 S锁 ,其实这是不严谨的,有时候想在读取记录时就获取记录的 X锁 ,来禁止别的事务读写该记录

对读取的记录加 S锁 : SELECT ... LOCK IN SHARE MODE;

对读取的记录加 X锁 : SELECT ... FOR UPDATE;

这里的X锁仍与S锁冲突(会阻塞)

当前读时(update、insert、delete,这些语句执行前都会查询最新版本的数据,然后再做进一步的操作)  会在读的范围上加一个间隙锁

写时的锁操作

DELETE :对一条记录做 DELETE 操作的过程其实是先在 B+ 树中定位到这条记录的位置,然后获取一下这条记录的 X锁 ,然后再执行 delete mark 操作(先标记 在事务提交后才由专门的线程做purge操作,把它加入到垃圾链表)。我们也可以把这个定位待删除记录在 B+ 树中位置的过程看成是一个获取 X锁 的 锁定读 

UPDATE:

如果未修改该记录的键值并且被更新的列占用的存储空间在修改前后未发生变化 则先在 B+ 树中定位到这条记录的位置,然后再获取一下记录的 X锁 ,最后在原记录的位置进行修改操作。其实我们也可以把这个定位待修改记录在 B+ 树中位置的过程看成是一个获取 X锁 的 锁定读 

如果未修改该记录的键值并且至少有一个被更新的列占用的存储空间在修改前后发生变化,则先在B+ 树中定位到这条记录的位置,然后获取一下记录的 X锁 ,将该记录彻底删除掉(就是把记录彻底移入垃圾链表),最后再插入一条新记录。这个定位待修改记录在 B+ 树中位置的过程看成是一个获取 X锁 的 锁定读 ,新插入的记录由 INSERT 操作提供的 隐式锁 进行保护。

如果修改了该记录的键值,则相当于在原记录上做 DELETE 操作之后再来一次 INSERT 操作,加锁操作就需要按照 DELETE 和 INSERT 的规则进行了。

注意后两种的区别 记录移入垃圾链表和DELETE操作是不同的文章来源地址https://www.toymoban.com/news/detail-579434.html

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

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

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

相关文章

  • MySQL中的锁机制详解

    事务的 隔离性 (隔离级别)是由锁来保证的。 并发访问数据的情况分为: 1.读-读 即并发事务相继读取相同的记录,因为没涉及到数据的更改,所以不会有并发安全问题,允许这种情况发生。 2.写-写 即并发事务对相同记录进行修改,会出现 脏写 问题,因为任何一种隔离级

    2024年02月06日
    浏览(38)
  • 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日
    浏览(35)
  • 【数据库】MySQL中的锁机制

    本系列包含: 【数据库】MySQL 的存储引擎 【数据库】B 树、B+ 树、索引 【数据库】从事务到锁机制 【数据库】MySQL 中的锁机制 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则。 MySQL 数据库由于其自

    2024年02月04日
    浏览(54)
  • java多线程之线程安全(重点,难点)

    由于操作系统中,线程的调度是抢占式执行的,或者说是随机的,这就造成线程调度执行时,线程的执行顺序是不确定的,虽然有一些代码在这种执行顺序不同的情况下也不会运行出错,但是还有一部分代码会因为执行顺序发生改变而受到影响,这就会造成程序出现Bug,对于多线程并发

    2024年01月25日
    浏览(51)
  • 说一下mysql的锁

    影响整个数据库的锁。例如,当执行 FLUSH TABLES WITH READ LOCK; 命令时,会阻止其他用户写入数据库,但可以读取。 全局锁是一种跨所有数据库实例的锁。它可以确保在任何时刻,只有一个事务能够访问共享资源。全局锁通常用于以下场景: 并发性较高的场景。 对数据一致性要

    2024年01月16日
    浏览(41)
  • 如何查看mysql里面的锁(详细)

    通过查询表统计信息查看 (1)查看当前有无锁等待 (2)查看哪个事务在等待(被阻塞了) 事务ID是3934 (3)查询该事务被哪个事务给阻塞了 从innodb_trx获取到被阻塞的trx_id是3934,阻塞该事务的事务id是3933 (4)根据trx_id,从innodb_trx表可查询到trx_mysql_thread_id线程id为970 (5)根

    2024年02月06日
    浏览(36)
  • 深入理解mysql的锁和mvcc

    1 锁讲解:面试必备-行锁、表锁 - 乐观锁、悲观锁的区别和联系 2 mvcc机制讲解(如何实现各种隔离级别):数据库基础(四)Innodb MVCC实现原理 刚读完上面两篇内容,可能会有很多疑惑的地方,下面是我自己整理出来的一些疑惑点: “RR” 是 “Repeatable Read”(可重复读)的

    2024年02月16日
    浏览(34)
  • MySql 数据库的锁机制和原理

    MySQL是一种流行的关系型数据库管理系统,广泛应用于各种Web应用程序和企业级应用程序中。在MySQL中,锁是一种用于控制并发访问的机制,它可以保证数据的一致性和完整性。本文将介绍MySQL的锁机制及原理,包括锁的类型、级别和实现原理等,并附上相应的代码示例。 在

    2024年02月05日
    浏览(74)
  • 字节跳动大厂面试题详解:java中有哪些类型的锁

    作者简介 :一名后端开发人员,每天分享后端开发以及人工智能相关技术,行业前沿信息,面试宝典。 座右铭 :未来是不可确定的,慢慢来是最快的。 个人主页 :极客李华-CSDN博客 合作方式 :私聊+ 这个专栏内容 :BAT等大厂常见后端java开发面试题详细讲解,更新数目10

    2024年02月21日
    浏览(48)
  • 面试之MySQL中的mvcc

     首先需要知道什么是 MVCC? MVCC 多版本并发控制。MVCC就是通过数据行的多个版本管理来实现数据库的并发控制。这项技术是的InnoDB的事务隔离级别下执行一致性读 有了保证。换言之,就是为了查询一些正在被一个事务更新的行。并且可以看到他们被更新之前的值。查询在做查

    2024年02月16日
    浏览(30)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包