【大厂面试05期】说一说你对MySQL中锁的了解?
这是我总结的一个表格,是本文中涉及到的锁(因为篇幅有限就没有包括自增锁)
| 加锁范围 | 名称 | 用法 |
|---|---|---|
| 数据库级 | 全局读锁 | 执行Flush tables with read lock命令各整个库接加一个读锁,处于只读状态。 |
| 数据库级 | 让全局只读 | 执行set global readonly=true命令可以让全库只能读 |
| 表级别 | 表锁 | lock tables test read让test表处于只读状态,所有事务都不能改表。lock tables test read让test表处于只读状态,所有事务都不能读表,只有当前事务可以更新表。 |
| 表级别 | 元数据锁(metadata lock,简写为MDL) | 在MySQL 5.5版本中引入了元数据锁,当对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁。主要是为了保证读写的正确性,不能一边读取表数据,一边修改表结构。 |
| 表级别 | 意向锁 | 意向锁的作用主要是表明当前表是否存在数据行加了行锁,在申请行级别的S锁之前会主动申请表级别的共享意向锁IS锁。在申请行级别的X锁之前会申请表级别的意向锁IX锁 |
| 行级别 | 记录锁 | 就是锁单个索引 |
| 行级别 | 间隙锁 | 就是锁索引之间的间隙,防止其他事务往这个间隙中插入新数据。 |
| 行级别 | 下一键锁(next key lock) | 就是记录锁+间隙锁,就是既锁索引,也锁索引之间的间隙。 |
1.数据库级别的锁
数据库级别的锁有以下两种:
1.1.全局读锁
对数据库执行Flush tables with read lock命令让整个库处于只读状态。
1.2.让全局只读
执行set global readonly=true这个命令也可以让全库只能读,但是第一有些系统会使用readonly来做一个操作,例如根据readonly是否为true判断数据库是否是从库,第二是如果执行这个命令后,客户端断开连接后,数据库会一直处于只读状态,如果是FTWRL命令发送异常会释放全局锁。(如果是从库,设置read-only对super user权限无效)
使用场景:
最常用的场景是对数据库备份。对数据库加锁,让整个数据库处于只读状态,所有更新操作停止(如果是主库就不能执行更新语句,从库也不能执行同步过来的bin log),然后对整个数据库做逻辑备份(就是将所有数据生成SQL写入备份文件。)
补充资料:
更好的进行数据库备份的一种方法
就是通过官方自带的逻辑备份工具mysqldump来进行逻辑备份时,设置一个参数-single-transaction,这样导数据的时候就会开启一个事务,这样利用innodb的mvcc机制可以保证在事务执行过程中,读到的数据都跟事务开始时的一致,并且执行过程中,其他事务可以执行更新操作, 不会对他造成影响(因为它就跟普通SELECT查询一样是读取的快照数据),这种方法必须要求数据库所有表的引擎都是innodb才行。
2.表级别的锁
表级别的锁有两种,一种是表锁,一种是元数据锁MDL。
2.1表锁 lock table
就是使用lock table user_table read/write命令来对表进行加读锁或者写锁。
加读锁(也就是表级别共享锁X锁)后,表对所有线程都是只能读,即便是当前线程也只能读表,不然会数据不一致。
加写锁后,表是对当前线程写,其他线程不能读,不能回数据不一致。
可以通过unlock tables来解锁,客户端断开时也会自动释放锁,但是影响所有线程,影响面太大了。这种锁我们一般也不会主动去调用,但是我们去更新一些数据时,如果查询条件是根据一些没有索引的字段去查询的,那样更新时会主动申请表锁中的写锁,获取成功后才能修改数据,事务提交成功之后,才会释放锁。(这也是为什么我们一般强调对于常用的查询字段加索引,就是为了提高更新和读取效率。)
2.2元数据锁MDL(MetaData Lock)
分为读锁和写锁,加读锁时,所有的线程都可以读表,加写锁时,只能一个线程写,其他的不能读。
锁不用显式使用,是访问一个表时,自动加上的。
对表进行增删改查时,会加读锁。
对表结构做修改时,会加写锁。
目的是为了在增删改查时不能修改表结构,修改表结构时不能去增删改查。
2.3 意向锁
意向锁的作用主要是表明当前表是否存在数据行加了行锁。这样事务可以根据当前表是否有意向锁来快速判断当前表是否存在数据行加了行锁,这样再加表级别的排斥锁X,共享锁S时,避免了去查询每一行数据,判断是否加了行锁,减小了性能开销。
意向共享锁(IS锁)
事务让一行数据只能读,需要申请对这行数据加行级别的共享锁S锁,在申请行级别的S锁之前会主动申请表级别的共享意向锁IS锁。
意向排斥锁(IX锁)
事务在更新某一行数据时,需要申请对这行数据加行级别的排斥锁X锁,在申请行级别的X锁之前会申请表级别的意向锁IX锁。
意向锁之间是兼容的,IS锁和IX是兼容,因为可能我们对第一行数据加S锁,那么会申请IS锁,对第二行数据加X锁,此时跟第一行的数据的S锁不冲突,所以也会先申请IX锁,由此可见,IS锁和IX之间不冲突,IS锁,IX锁与行级别的S,行级别的X之间也不冲突。
意向锁只是跟表级别的S,X锁可能会冲突。
| 表级别的S锁 | 表级别的X锁 | |
|---|---|---|
| 意向共享锁IS | 兼容 | 不兼容 |
| 意向排斥锁IX | 不兼容 | 不兼容 |
行级别的锁
行锁是innodb引擎特有的锁,也是分为共享锁(也就是通常说的读锁)和互斥锁(也就是通常说的写锁)
共享锁 S锁,就是读锁,允许事务读一行数据,不能被修改。所以读锁之间不排斥
互斥锁 X锁,就是写锁,就是让当前事务可以修改这行数据,其他事务不能修改这行数据
如果是从加锁的范围来区分,行锁主要分为记录锁(锁单个索引),间隙锁(锁索引之间的间隙),下一键锁(等于记录锁+间隙锁)
记录锁 record lock
记录锁锁定的是单条索引记录。例如 SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE; ,如果c是主键或者是一个唯一性索引的字段,由于在表内唯一,所以只需要对c=10这个索引进行加锁,可以防止其他事务插入,更新或删除这个数据行。
间隙锁 gap lock
间隙锁就会对记录之间的间隙加锁,防止数据插入。
下一键锁 next-key lock
next-key lock是 record lock 和 gap lock的组合,就是会对索引记录加记录锁 + 索引记录前面间隙上的锁”,就是对要更新的数据的左右两个端点加间隙锁。
具体案例:
因为innodb默认的隔离级别是可重复读,我们在执行更新语句和使用当前读语句(SELECT…FOR UPDATE)时,都是需要加一些行锁的,来防止其他事务插入或者删除数据,导致在事务内多次读取到的数据行不同。针对行锁的加锁规则,极客时间中丁奇老师总结了以下四条规则:
- 原则1:加锁的基本单位是next-key lock。希望你还记得,next-key lock是前开后闭区间。
- 原则2:查找过程中访问到的对象才会加锁。
- 优化1:索引上的等值查询,给唯一索引加锁的时候,next-key lock退化为记录锁。
- 优化2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化为间隙锁。
- 一个bug:唯一索引上的范围查询会访问到不满足条件的第一个值为止。
简单的来说,我认为就是next-key lock就是加锁的基本单位,只不过innodb做了很多优化,在不需要对那么大范围的数据行加锁时,会进行降级,降级为间隙锁,或者是记录锁。
下面就来看一个具体的例子
例如:
a是一个普通字段,对它建了索引,在数据库中对应a这个字段存在的值已经有1,5,10,20,30
那么根据next-key lock来划分区间,next-key lock是根据已有数据行来划分区间,并且是左开右闭区间,所以可以锁定的区间是
(负无穷,1]
(1,5]
(5,10]
(10,20]
(20,30]
(30,正无穷)
//更新操作
update table set b = '1' where a = 10;
在innodb中执行更新操作,
- 如果a是唯一性索引,根据原则3那么只需要对a为10的这条索引加记录锁就行了,因为不用担心其他事务再插入一条a为10的数据,因为插入时会有唯一性判断。
- 但是如果a是非唯一性索引,如果只是对a=10这个索引加锁,可能会有其他事务插入a=10的数据行,所以会对(5,10]和(10,20]这两个区间加锁,并且根据上面的原则4,会将(10,20]降级为间隙锁,也就是只对(10,20)加锁,因为a=20这个索引是否加锁都不影响当前的事务。
- 如果a没有索引,需要插入时会先申请表级别的互斥锁X锁,然后进行插入。
【大厂面试05期】说一说你对MySQL中锁的了解?的更多相关文章
- 【大厂面试07期】说一说你对synchronized锁的理解?
synchronized锁的原理也是大厂面试中经常会涉及的问题,本文主要通过对以下问题进行分析讲解,来帮助大家理解synchronized锁的原理. 1.synchronized锁是什么?锁的对象是什 ...
- 【大厂面试02期】Redis过期key是怎么样清理的?
PS:本文已收录到1.1K Star数开源学习指南--<大厂面试指北>,如果想要了解更多大厂面试相关的内容,了解更多可以看 http://notfound9.github.io/inter ...
- 【大厂面试03期】MySQL是怎么解决幻读问题的?
问题分析 首先幻读是什么? 根据MySQL文档上面的定义 The so-called phantom problem occurs within a transaction when the same ...
- 【大厂面试08期】谈一谈你对HashMap的理解?
摘要 HashMap的原理也是大厂面试中经常会涉及的问题,同时也是工作中常用到的Java容器,本文主要通过对以下问题进行分析讲解,来帮助大家理解HashMap的原理. 1.HashMap添加一个键值对 ...
- 【大厂面试06期】谈一谈你对Redis持久化的理解?
Redis持久化是面试中经常会问到的问题,这里主要通过对以下几个问题进行分析,帮助大家了解Redis持久化的实现原理. 1.Redis持久化是什么? 2.Redis持久化有哪些策略?各自的实现原理是怎 ...
- 【大厂面试04期】讲讲一条MySQL更新语句是怎么执行的?
流程图 这是在网上找到的一张流程图,写的比较好,大家可以先看图,然后看详细阅读下面的各个步骤. 执行流程: 1.连接验证及解析 客户端与MySQL Server建立连接,发送语句给MySQL Serv ...
- 《大厂面试》京东+百度一面,不小心都拿了Offer
你知道的越多,你不知道的越多 点赞再看,养成习惯 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试点思维导图,也整理了很多我的文档,欢迎Star和 ...
- 《HelloGitHub月刊》第05期
<HelloGitHub>第05期 兴趣是最好的老师,<HelloGitHub>就是帮你找到兴趣! 欢迎各路人士加入本项目,丰富月刊的内容,也可以直接在Issue(需要登录gi ...
- 【Android UI设计与开发】第05期:引导界面(五)实现应用程序只启动一次引导界面
[Android UI设计与开发]第05期:引导界面(五)实现应用程序只启动一次引导界面 jingqing 发表于 2013-7-11 14:42:02 浏览(229501) 这篇文章算是对整个引导界 ...
随机推荐
- nth-of-child和nth-of-type的区别
p:nth-of-child(2) 翻译过来就是,必需是p元素,并且是父标签的第二个元素,满足以上两个条件,这些样式才会渲染. p:nth-of-type(2) 翻译过来就是,必需是p ...
- 05.django 搜索与过滤
django-filter https://github.com/carltongibson/django-filter https://django-filter.readthedocs.io/en ...
- Objective-C中的加号与减号
在Objective-C中,方法分为类方法和实例方法. 前置加号(+)的方法为类方法,这类方法是可以直接用类名来调用的,它的作用主要是创建一个实例.有人把它称为创建实例的工厂方法. 前置减号(-)的方 ...
- Jmeter(二) - 从入门到精通 - 创建测试计划(Test Plan)(详解教程)
1.简介 上一篇中宏哥已经教你把JMeter的测试环境搭建起来了,那么这一篇我们就将JMeter启动起来,一睹其芳容,首先宏哥给大家介绍一下如何来创建一个测试计划(Test Plan). 2.创建一个 ...
- 可持续字典树 Perfect Security
题目链接 题目大意:给你两个序列,第二个序列可以任意进行排列变换,然后由这两个序列一一异或得到答案序列,要求答案序列的字典序最小. 可持续字典树与第K大可持续线段树的区别主要在于每个节点上 ,它多了一 ...
- Understanding REST and RESTful APIs
Understanding REST and RESTful APIs If you've spent any amount of time with modern web development, ...
- javascript图片加载完成前显示loading图片
<html> <title>图片预加载</title> <body> <script> //判断浏览器 var Browser=new Ob ...
- Pygame 框架安装教程(Python3.6为例)
1.python版本是3.6,最新的pygame是1.9.3,这两个最好都用32位的. pygame1.9.3下载地址:http://www.lfd.uci.edu/~gohlke/pythonlib ...
- webpack-dev-server 使用 react-router 启用 browserhistory 采坑记
问题的产生 今天下午请假,忙完手头事之后,在家实在无聊,想着从0开始搭建一个 react 的项目.webpack 基本配置之前研究过,没什么大问题.谁想,在 react-router 的配置时出现了个 ...
- 发光加载环动画-纯CSS动画效果-如何创建CSS3旋转预加载器(参照https://www.bilibili.com/video/BV1V4411C7z5?from=search&seid=9741275927942612817)
//css部分 body{ margin:; padding:; background: #262626; } .ring{ position: absolute; top:50%; left: 50 ...