跟面试官侃半小时MySQL事务隔离性,从基本概念深入到实现
来源 | 阿丸笔记
提到MySQL的事务,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关。
而事务的ACID(即原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability)可以说涵盖了事务的全部知识点,所以,我们不仅要知道ACID是什么,还要了解ACID背后的实现,只有这样,无论在日常开发还是面试求职,都能无往而不利。
为了大家更好的阅读体验,对ACID的深入分析将分为上下两篇。
本篇为上篇,主要围绕ACID中的I,也就是“隔离性”展开,从基本概念,到隔离性的实现,最后以一个实战案例进行融会贯通。
嗯,看完全部内容你都能理,那跟面试官侃半小时隔离性就没问题了。
事务隔离性的基本概念
1.1 什么是ACID中的Isolation,隔离性
Isolation,隔离性,也有人称之为并发控制(concurrency control)。事务的隔离性要求每个事务读写的对象对其他事务都是相互隔离的,也就是这个事务提交前,这个事务的修改内容对其他事务都是不可见的。事务的隔离性,主要是解决不同事物之间的相互读写影响。
所谓的读写影响注意分为三种:
脏读:读到了别的事务尚未提交(commit)的变更,别人没提交,我读到了。
不可重复读:别的事务提交了变更,被当前事务读到了。然后导致本事务多次select的结果不一样,读到了别的事务提交的内容。
幻读:也是读到了别的事务提交的内容,但是跟上面的不同之处在于,读到了原本不存在的记录。
注意,不可重复读,主要是读到了别的事务update的内容。而幻读,是读到了别的事务insert的内容。
1.2 隔离性的隔离级别
为了解决事务隔离性的问题,数据库一般会有不同的隔离级别来解决相应的读写影响。
读未提交:一个事务B还没提交,它的修改就被别的事务A读到了。
读已提交:一个事务B提交后,它的修改被其他事务A看到了。
可重复读:一个事物B提交前和提交后,事务A都无法读到事务B的变更。
串行化:对同一行记录,当出现不同事物的读写冲突时,是通过串行化的方式解决的,后一个事务必须等前一个事务完成才能执行。
不同隔离级别能够解决不同的隔离性问题。
需要注意的是,这是标准事务隔离级别的定义。在MySQL的innodb引擎中,在可重复读级别下,通过mvcc解决了幻读的问题,具体实现我们后面再讲。
同时,需要注意的是,到目前为止,我们说的读,都是”快照读”,普通的select。后面我们还会提到“当前读”,是不一样的哦。
事务隔离性的实现
要实现事务的隔离性,需要了解两个方面的内容,一个是锁,一个是多版本并发控制(MVCC)。
2.1 事务的行锁
InnoDB中,实现了两种标准的行级锁:
共享锁(S Lock),也叫读锁,允许事务读取一行数据。
排它锁(X Lock),也叫写锁,允许事务删除或者更新一行数据(注意,这里没有提到插入哦,插入涉及到幻读,可以看文章最后的说明)
普通select语句不会有任何锁,那么如何获得共享锁和排它锁呢?
Select … lock in share mode语句能够获得共享锁
Select … for update(特殊的select,用mysql简单实现分布式锁经常用它)、Update、delete语句能够获得排它锁
当一个事务A已经获得了行r的共享锁,那么另一个事务B可以立刻获得行r的共享锁,因为不会改变r的数值,这种叫做锁兼容。
如果这时候有事务C希望获得行r的排它锁,那么就必须等待事务A和事务B释放行r的共享锁之后,才能获得排它锁,这种叫做锁不兼容。
普通的select不会对行上锁,而select…lock in share mode会上共享锁,select…for update会上排它锁。
对于普通的select的读取方式,称为”快照读“,也叫”一致性非锁定读“。
对于带锁的select读取,或者update tb set a = a+1(读取a的当前值),称为“当前读”,也叫“一致性锁定读”。
如果在update、insert的时候,不能进行select,那么服务的并发访问性能就太差了。因此,我们日常的查询,都是“快照读”,不会上锁,只有在update\insert\“当前读”的时候,才会上锁。而为了解决“快照读”的并发访问问题,就引入了MVCC。
2.2 多版本并发控制MVCC
如果说上面的行锁是一种悲观锁,那么MVCC就是一种乐观锁的实现方式,而且是一种很常用的乐观锁实现方式。
所谓多版本,就是一行记录在数据库中存储了多个版本,每个版本以事务ID作为版本号。InnoDB 里面每个事务有一个唯一的事务 ID,是在事务开始的时候向InnoDB的事务系统申请的,并且按照申请顺序严格递增的。假如一行记录被多个事务更新,那么,就会产生多个版本的记录。
以某一行数据作为例子:
经过两次事务的操作,value从22变成了19,同时,保留了三个事务id,15、25、30。
在每个记录多版本的基础上,需要利用“一致性视图”,来做版本的可见性判断。
这里,我们要区分MySQL里面的两个”视图”概念:
一个是view,通过语法create view … 实现,主要创建一个虚拟表,用来执行查询语句。
一个是InnoDB用来实现mvcc的一致性视图(consistent read view),纯逻辑概念,没有物理结构,定义了在事务期间,你能看到哪些版本的数据。
我们全文提到的“视图”都是第二种,主要是支持InnoDB在“读已提交”和“可重复读”级别的并发访问问题。
“读未提及”级别下,没有一致性视图
“读已提交”级别下,会在 每个SQL开始执行的时候 创建一致性视图
“可重复读”级别下,会在 每个事务开始的时候 创建一致性视图
“串行化”级别下,直接通过加锁避免并发问题
下面,我们简单介绍一下创建一致性视图的逻辑。
以“可重复读”级别为例。
当一个事务开启的时候,会向系统申请一个新事务id
此时,可能还有多个正在进行的其他事务没有提交,因此在瞬时时刻,是有多个活跃的未提交事务id
将这些未提交的事务id组成一个数组,数组里面最小的事务id记录为低水位,当前系统创建过的事务id的最大值+1记录为高水位
这个数组array 和 高水位,就组成了“一致性视图”。
有了一致性视图后,我们就可以判断一行数据的多版本可见性了,无论是“读已提交”还是“可重复读”级别,可见性判断规则是一样的,区别在于创建快照(一致性视图)的时间。
在当前事务中,读取其他某一行的记录,对其中的版本号的可见性判断有五种情况(建议自己跟着捋一捋,挺重要的):
如果版本号小于“低水位”,说明事务已经提交,那肯定 可见;
如果版本号大于“高水位”,说明这行数据的这个事务id版本是在快照后产生的,那肯定 不可见;
如果版本号在事务数组array中,说明这个事务还没提交,所以 不可见;
如果版本号不在事务数组array中,且低于高水位,说明这个事务已经提交,所以 可见;
当然,无论什么时候,自己的事务id中的任何变化,都是可见的
可以看看下面这个例子,更容易理解。
系统创建过的事务id:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
事务A启动,拍个快照
此时未提交的事务id有:7,8,9
一致性视图:数组array[7,8,9] + 高水位16(15+1)
对于任意一行数据的可见性判断:
小于7的,可见
大于16的,说明是快照后产生的,不可见
10-15,不在数组array中,说明已经提交了,可见
7,8,9在array中,说明未提交,不可见
两个重要结论:
InnoDB 利用了“所有数据都有多个版本”的这个特性,实现了“秒级创建快照”的能力。
MVCC的实现,就是根据当前事务的事务id为依据创建“一致性视图”,利用一致性视图来判断数据版本的可见性。
隔离性实战
下面,我们来两个实战案例,将上面的基础概念与实现融会贯通吧。
1)并发select&update 案例
id=1 的value初始为1。
我们看下,在不同隔离级别,Time5、Time7、Time9事务A查询到的value 分布为多少。
“读未提交”:2,2,2
“读以提交”:1,2,2
“可重复读”:1,1,2
串行化:1,1,2(注意,这里在事务A提交前,事务B都会阻塞,直到事务A提交后才能执行)
2)并发update案例
id=1 的value初始为1,在可重复读级别:
我们看一下,你猜猜事务A和事务B读取的value是多少?
答案是:1 和 3
可能会产生困惑,事务A在启动后快照,所以读到了1是正常的,但是事务2在启动的时候快照了,然后在自己的事务中+1,怎么会读到3而不是2呢?
原因很简单,即使是在可重复读的级别,事务 更新数据 的时候,只能用当前读(想想也能理解,不然update就出现数据不一致了)。
如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。而读提交的逻辑和可重复读的逻辑类似,它们最主要的区别是:在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。
这里,我们需要注意的是事务的启动时机。
begin/start transaction 命令并不是一个事务的起点,在执行到它们之后的第一个操作 InnoDB 表的语句,事务才真正启动,一致性视图是在执行第一个快照读语句时创建的。
如果你想要马上启动一个事务,可以使用 start transaction with consistent snapshot 这个命令,一致性视图是在执行 start transaction with consistent snapshot 时创建的。
关于幻读
前文已经提到了,对于普通数据库,需要到可串行化的隔离级别才能解决幻读问题。
而对于InnoDB存储引擎来说,在可重复读级别下就能解决幻读问题。
InnoDB存储引擎有三种行锁算法:
行锁:当个行记录上的锁
间隙锁:Gap Lock,锁定一个范围,但不包含记录本身
Next-Key Lock:就是行锁+间隙锁,同时锁上一个范围,并且锁定记录本身
InnoDB就是通过Next-Key Lock解决了幻读的问题。
好了,关于ACID的隔离性就说到这里,你有什么看法,欢迎在评论区和我们讨论。
「AI大师课」是CSDN发起的“百万人学AI”倡议下的重要组成部分,4月份AI大师课以线上技术峰会的形式推出,来自微软、硅谷TigerGraph、北邮等产学界大咖就图计算+机器学习,语音技术、新基建+AI、AI+医疗等主题展开分享,扫描下方二维码免费报名,限时再送299元「2020AI开发者万人大会」门票一张。
推荐阅读:一文教你如何使用 MongoDB 和 HATEOAS 创建 REST Web 服务
一个数据科学家需要哪些核心工具包?
AI 开发者不容错过的 20 个机器学习和数据科学网站
马云为什么救援世界?
1分钟售出5万张票!电影节抢票技术揭秘
BTC重现“自由落体”式暴跌,原来是受这几个因素影响?
真香,朕在看了!
跟面试官侃半小时MySQL事务隔离性,从基本概念深入到实现相关推荐
- 事物与持久化_跟面试官侃半小时MySQL事务,说完原子性、一致性、持久性的实现...
提到MySQL的事物,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关. 而事务的ACID(即原子性Atomicity.一致性Consiste ...
- 跟面试官侃了半小时 MySQL 事务,把原子性、一致性、持久性的实现都讲完了
来源 | 阿丸笔记 封图| CSDN下载于视觉中国 提到MySQL的事务,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关. 而事务的ACID ...
- 看了这个文章你也可以和面试官侃半个小时hashMap了
HashMap应该算是Java后端工程师面试的必问题,因为其中的知识点太多,很适合用来考察面试者的Java基础. 面试官: 你先自我介绍一下吧! 我: 我是安琪拉,草丛三婊之一,最强中单(钟馗不服)! ...
- 【Spring】3.助你跟面试官侃一个小时的AOP
使用 代理模式 是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系 ...
- MySQL数据库事务隔离性的实现
摘要:事实上在数据库引擎的实现中并不能实现完全的事务隔离,比如串行化. 本文分享自华为云社区<[数据库事务与锁机制]- 事务隔离的实现>,原文作者:技术火炬手 . 事实上在数据库引擎的实现 ...
- mysql数据库事务有几种特性_面试官:你能说说事务的几个特性是啥?有哪几种隔离级别?...
1.面试题事务的几个特点是什么? 数据库事务有哪些隔离级别? MySQL的默认隔离级别?2.面试官心里分析 用mysql开发的三个基本面:存储引擎.索引,然后就是事务,你必须得用事务. 因为一个业务系 ...
- 大厂面试官必问的Mysql锁机制
前言 前几天有粉丝和我聊到他找工作面试大厂时被问的问题,因为现在疫情期间,找工作也特别难找.他说面试的题目也比较难,都偏向于一两年的工作经验的面试题. 他说在一面的时候被问到Mysql的面试题,索引那 ...
- 面试官:你能说说事务的几个特性是啥?有哪几种隔离级别?
本文转载自公众号:石杉的架构笔记 目录 1.面试题 2.面试官心理分析 3.面试题剖析 1.面试题 事务的几个特点是什么? 数据库事务有哪些隔离级别? MySQL的默认隔离级别? 2.面试官心里分析 ...
- mysql编写完怎么执行_面试官:一条MySQL更新语句是如何执行的?
在面试中面试中如果被面试官问到在MySQL中一条更新语句是怎么执行的?,下面让我们来探究一下! 流程图 这是在网上找到的一张流程图,写的比较好,大家可以先看图,然后看详细阅读下面的各个步骤. 执行流程 ...
最新文章
- 使用现代C++如何避免bugs(下)
- 编码不规范,同事真的会两行泪?
- git用法从入门到精通
- 怎么在代码中打开、关闭屏幕旋转
- 使用Opencv构建一个简单的图像相似检测器(MSE、SSIM)
- Wpf 调用线程无法访问此对象,因为另一个线程拥有该对象,解决方案
- [JavaWeb-HTML]HTML概念介绍和快速入门
- python 随机_python1到3秒随机延时入坑python 心情舒畅
- hdu1505 dp:01矩形中最大面积全0矩阵
- php数据库模式,具有singleton模式的PHP数据库类[closed]
- radix在Character.MIN_RADIX与Character.MAX_RADIX之间
- 详解IP地址和Mac地址
- 迷宫问题的求解(广度和深度优先搜索)
- 原来window7系统转化为xp的时候,安装系统的时候,出现蓝屏错误(stop:0x0000007b)
- simulink多输入示波器波形数据导出到workspace用plot函数重新画出
- tableau各种精典示例经验总结02
- word内多级列表标题变成黑块解决办法
- java-php-python-ssm田径运动会成绩管理系统计算机毕业设计
- 显示网络没有服务器地址,tcp/ip cp报告了错误738:服务器没有指派地址
- mysql 前端后端_前端开发者学习后端(一) —— mysql 命令
热门文章
- 基于php的外卖订餐系统开题报告_订餐系统开题报告.doc
- linux设备树例程,iTOP-iMX6-设备树内核-实时时钟RTC以及Linux-c测试例程
- 安卓手机软件开发_无代码手机app软件开发,让人人都是专业开发工程师
- 钱学森做的试卷你见过吗?100年前学霸的笔记,工整得像打印的
- 费城中餐馆奇葩鸡翅定价引爆网络,数万网友想要破解数学谜题
- 宁浩:扛过了,痛便是痛快!
- 拉力测试软件界面,电脑拉力机/电脑控制拉力试验机软件操作界面与功能
- web通讯录之登录注册界面
- 语音识别学习日志 2019-7-13 语音识别基础知识准备 1{语音基础知识}
- 宜搭小技巧|自动计算日期时长,3个公式帮你敲定