前言
最近在准备春招的过程中顺手复习了一下MySQL的事务隔离级别,现在整理出来和各位同学一起学习,若有不对的地方请指教。
在这之前先看看相关的面试题:
- MySQL有哪些事务隔离级别?
-
Read Commit(读已提交)
级别是如何解决脏读
的? -
Repeatable Read(可重复读)
级别是如何解决不可重复读
的? - MySQL是如何解决
幻读
的?MVCC
可以解决幻读问题吗?
相关概念
首先先介绍一下脏读、不可重复读和幻读:
脏读:指一个事务可以看到另一个事务未提交的数据。
比如说事务A修改了一个值但是还未提交,这时事务B可以看到A修改的值,这就是脏读。
不可重复读:一个事务执行两次同样的查询语句,前后得出的数据却不一致。
比如说事务A执行了select语句,事务B修改了某个值,事务A再次执行select语句时发现结果和上次不一致,因此叫做不可重复读。
幻读:在同一个事务中,同一个查询多次返回的记录行数不一致(这里的结果特指查询到的记录行数,幻读可以看做不可重复读的一种特殊情况)。
比如说事务A执行了select语句,事务B插入数据,事务A再次执行select语句时发现多了几条记录,好像出现了幻觉一样,因此叫做幻读。
MySQL有哪些事务隔离级别?
级别从低到高分别是:未提交读
、已提交读
、可重复读
、串行化
下图是各个隔离级别以及可能会出现的问题:
Read Commit(读已提交)级别是如何解决脏读的?
先说结论:通过改变锁的释放时机来解决脏读问题。
首先先了解一下为什么会出现脏读?原因就是在未提交读
这个级别下,当事务A修改了数据之后就立马释放了锁,因此事务B可以读取到这个未提交的数据。
在已提交读
级别下写操作加的锁会到事务提交后释放,所以事务B不会读到事务A未提交的数据,通过改变锁的释放时机解决了脏读的问题。
Repeatable Read(可重复读)级别是如何解决不可重复读的?
结论:可重复读
级别就是通过MVCC
机制来解决不可重复读问题的
MVCC机制(多版本并发控制)
就我个人理解来说其实就是给每行数据都添加了几个隐藏字段,用来表示数据的版本号,即一个数据在mysql中会有多个不同的版本,想深入了解MVCC请参考:MVCC机制
MVCC就是给每一行都都有个事务版本号,假设一条链表第一个节点是最新的数据,越后数据越旧,当有一个快照读操作过来后,会遍历链表,找到第一个当前事务可见的数据。
有了MVCC之后我们可以把SQL操作分为两类:
- 快照读
读取当前事务可见的数据,默认的select操作就是快照读,读的是历史版本的数据。
- 当前读
读取最新的数据,除了默认select操作外的select..for update
、update
、insert
、delete
等操作都是当前读,读取的都是最新的数据。
现在我们有了MVCC,当事务A执行一个普通的select操作(快照读)
,MySQL会把这次读取的数据保存起来,在这期间不管事务B执行update或是insert操作,事务A再次执行select操作读取到的数据是不会变的,因此通过可重复读级别通过MVCC解决了不可重复读问题,顺便解决了部分的幻读问题
,没错MVCC并没有解决所有的幻读问题,只是解决了一部分,那是如何彻底解决幻读问题的呢?请接着往后看。
MySQL是如何解决幻读的?MVCC可以解决幻读问题吗?
先说结论:MVCC并不能解决所有的幻读问题,MySQL是通过MVCC + Next Key Lock来解决幻读问题的。
为什么MVCC不能解决幻读?
因为当事务执行的是加锁的select操作(当前读
),每次执行都是读取最新的数据,事务A是可以看到事务B修改的数据的,那么还是会出现幻读的问题,因此MySQL引入了一种叫做Next Key Lock
的算法,简单来说就是对一个范围加锁,这样子当事务A执行select..for update
时会对数据加锁,这时事务B是无法执行update
、insert
等操作的,因此MySQL是通过MVCC + Next Key Lock来解决幻读问题的,有关Next Key Lock请参考Innodb锁机制:Next-Key Lock 浅谈
总结
有关MySQL隔离级别就讲到这里啦,这些都是本人的一些心得,如果有什么不对的地方请各位大佬们多多指教!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。