NingG +

MySQL 技术内幕:事务隔离级别和MVCC

几点:

事务是什么?

事务(Transaction),一组数据库操作,作为单个逻辑单元。

几个特性

事务具有4个属性:ACID,原子性、一致性、隔离性、持久性。

隔离级别

事务有隔离性(Isolation),并发事务间相互独立,互不干扰;几个要点:

并发事务,相互干扰的现象

并发事务,相互干扰的几类现象:

并发事务,隔离级别

通过设定不同的隔离级别,来解决上述的脏读、不可重复读、幻读的现象,具体:

Tips:

大部分数据库系统,默认隔离级别:读取已提交;MySQL默认,可重复读。

不同隔离级别对应的现象,见下表:

隔离级别 脏读 不可重复读 幻读
读取未提交 Y Y Y
读取已提交 N Y Y
可重复读 N N Y
序列化 N N N

MySQL中隔离级别

隔离级别,用于表述并发事务之间的相互干扰程度,其基于锁机制进行并发控制。

1. 可序列化 Serializable

实现可序列化要求在选定对象上的读锁和写锁保持直到事务结束后才能释放。在 SELECT 的查询中使用一个 WHERE 子句 来描述一个范围时应该获得一个“范围锁(range-locks)”。这种机制可以避免“幻读(phantom reads)”现象。

2. 可重复读 Repeatable read

该级别保证了同一个事务中多次读取同样的记录的结果是一致的。

选定对象读锁(read locks)和写锁(write locks)一直保持到事务结束,但不要求“范围锁(range-locks)”,因此可能会发生“幻读(phantom reads)”。

幻读:是因为没有保持范围锁,该事务执行了一个 where 子句的范围查询后,其他事务可能新增了一条处于该事务 where 查询范围内的记录,那么该事务再次执行范围查询时就会看到这些新增的记录行(幻行,Phantom row)。

可重复读是 MySQL 的默认事务隔离级别。

3. 读取已提交 Read committed

DBMS需要对选定对象的写锁(write locks)一直保持到事务结束,但是读锁(read locks)在SELECT操作完成后马上释放(因此“不可重复读”现象可能会发生,见下面描述)。和前一种隔离级别一样,也不要求“范围锁(range-locks)”。

不可重复读是因为,事务只维持了选定对象的写锁,如果一些选定对象只涉及读锁,那么在读锁释放之后,其它事务可以对这些对象进行修改,该事务再次读取时就不一致了。例如,事务A对数据对象拥有写锁,事务B读取了数据对象,后事务A有对数据对象进行的更改并提交,事务B再次读取数据对象,两次读取结果不同。

大多数数据库的默认事务隔离级别都是这个。

4. 未提交读 Read uncommitted

也称为脏读(dirty read)。

一个事务可以读取到其它事务未提交的更改。

注意:

MySQL中多版本并发控制(MVCC)

MVCC 整体思路

整体思路:

  1. 多版本并发控制(MVCC),来实现 MySQL 上的多事务并发访问时,隔离级别控制;
  2. 数据版本:并发事务执行时,同一行数据有多个版本
  3. 事务版本:每个事务都有一个事务版本
  4. 版本有序:版本是通过时间来标识的
    • 数据版本:包含创建版本(创建时间)、删除版本(删除时间)
    • 事务版本:事务的创建时间,作为事务版本
    • Note:数据版本,并不包含更新版本(更新时间),因为,在多事务并发情况下,更新操作,实际是:删除原数据 + 新增新数据

通过 MVCC 实现一种效果:

同一时刻同一张表,多个并发事务,看到的数据是不同的:

  1. 事务的版本
  2. 数据的版本

MVCC 小结:

  1. MVCC,本质使用了copy-on-write(写时复制),为每个数据保留多份 snapshot;
  2. 不同 snapshot 之间,使用指针连接成链表
  3. update 操作,能看到的 snapshot 是受限的,是链表上,小于等于当前事务版本的最大版本(读取已提交:离当前事务最近已提交版本)
  4. update 操作,创建一个新的 snapshot,并使用事务版本,作为创建版本;

MVCC 细节

多版本并发控制(MVCC)的实现是通过保存数据在某个时间点的快照来实现的。根据事务的创建时间不同,多个并发事务对同一张表,同一时刻看到的数据可能是不一样的。

InnoDB 的 MVCC 是通过在每行记录后面保存两个隐藏的列来实现的:

存储的实际值是系统版本号(system version number)。

每开始一个新的事务,系统版本号都会递增。事务开始时刻的系统版本号作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

可重复读 隔离级别下,MVCC 的具体操作:

MVCC 历史数据清理

多版本并发控制(MVCC),只发生在:并发事务访问的时候,同一行数据,可能存在多个版本。

那有个问题:并发事务访问结束后,什么时候清除历史版本数据?

MySQL修改事务隔离级别

todo:

参考来源

Top