MySQL隔离级别的实现

172 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情

概述

前面几篇分别对MySQL的索引和事务都分别做了分析。其中主要包含事物的特性、事务导致的问题、事务通过不同的隔离级别解决事务导致的问题,最后也对事务隔离级别解决事务导致的问题的解决方案做了分析,其中包括使用快照和锁的方案。今天主要是对事务这块的知识做一个简单的小结。

重温InnoDB 隔离级别

第一个隔离级别叫做:Read Uncommitted(未提交读),一个事务可以读取到其他事务未提交的数据,会出现脏读,所以叫做RU,它没有解决任何的问题。

第二个隔离级别叫做:Read Committed(已提交读),也就是一个事务只能读取到其他事务已提交的数据,不能读取到其他事务未提交的数据,它解决了脏读的问题,但是会出现不可重复读的问题。

第三个隔离级别叫做:Repeatable Read (可重复读),它解决了不可重复读的问题,也就是在同一个事务里面多次读取同样的数据结果是一样的,但是在这个级别下,没有定义解决幻读的问题。

最后一个就是:Serializable(串行化),在这个隔离级别里面,所有的事务都是串 行执行的,也就是对数据的操作需要排队,已经不存在事务的并发操作了,所以它解决了所有的问题

MySQL InnoDB 对隔离级别的支持

MySQL InnoDB里面,不需要使用串行化的隔离级别去解决所有问题。那我们来看一下 MySQL InnoDB里面对数据库事务隔离级别的支持程度是什么样的。

事务隔离级别脏读不可重复读幻读
未提交读(Read Uncommitted)可能可能可能
已提交读(Read Committed)不可能\color{red}{不可能}可能可能
可重复读(Repeatable Read)不可能\color{red}{不可能}不可能\color{red}{不可能}InnoDB不可能\color{blue}{对InnoDB不可能}
串行化(Serializable)不可能\color{red}{不可能}不可能\color{red}{不可能}不可能\color{red}{不可能}

Read Uncommited

RU 隔离级别:不加锁。

Serializable

Serializable 所有的 select 语句都会被隐式的转化为 select ... in share mode,会和 update、delete 互斥。

这两个很好理解,主要是 RR 和 RC 的区别?

Repeatable Read

RR 隔离级别下,普通的 select 使用快照读(snapshot read),底层使用 MVCC 来实现。

加锁的 select(select ... in share mode / select ... for update)以及更新操作update, delete 等语句使用当前读(currentread\color{red}{前读(current read)},底层使用记录锁、或者间隙锁、临键锁\color{red}{记录锁、或者间隙锁、 临键锁}

Read Commited

RC 隔离级别下,普通的 select 都是快照读,使用 MVCC 实现。

加锁的 select 都使用记录锁,因为没有 Gap Lock。

除了两种特殊情况——外键约束检查(foreign-key constraint checking)以及重复键检查(duplicate-key checking)时会使用间隙锁封锁区间。

所以 RC 会出现幻读的问题。