Transactions (3-2) - Weak Isolation Levels - Snapshot Isolation

Day 3

Snapshot Isolation 和 Repeatable read

先来看个 read committed 等级的隔离下会发生的灵异现象吧!如下图的 Alice 在银行各存了 500 元在两个帐户中,总额 1000 元,尔後有个 transaction 执行 100 元的转帐作业,如果 Alice 在转帐前查了 Account 1,而在转帐结束後才去查了 Account 2, 会发现两个帐户的总金额为 900 元,100 元消失在空气中了,比被通膨吃掉还惨。

这种异常情形称 nonrepatable readread skew,尽管 Alice 在查一次就正常了,但有些情况则不允许这种不一致发生:

  • 备份 (Backup)

    备份作业通常需要整个资料库的复制,如果在备份期间发生 read skew,若不幸要用该备份复原资料的话,Alice 的 100 元就真的消失了。

  • 分析需求和资料检查

    有时分析需求需要查大量的资料,或者资料需要定期做检查(监测腐坏资料),这 2 种情形都会造成无意义且会浪费人力资料的结果。

快照隔离 (Snapshot Isolation) 一般是解决 read skew 问题的方式,其概念就是每一个 transaction 开始时,都是从一致 (consitent) 的快照中读取资料,期间即使其他 transaction 已经修改资料了(已 commit),该 transaction 还是一样会读旧的资料,可以想像成资料就被冻结在 transaction 开始的时间点,它尤其适合用在长时间的 transaction 上。

实现快照隔离 (Snapshot Isolation)

就像实现 read committed 那般,避免 dirty write 的方式也是使用物件锁,避免 dirty read 则不能使用任何锁,我们首先要确保 写入跟读取不会互相影响,所以为了实现快照隔离,资料库需要一个机制去保存不同版本的物件资料,因为多个 transaction 可能会在同个时间点看到多个快照的物件资料,该机制称为 MVCC 多版本并发控制 (multi-version concurrent control)

如果资料库支援快照隔离,则前一小节讲的 read committed 隔离就能一起使用 MVCC 实作了,差别只是 read committed 是在同个 transaction 下的每一次查询都拿不同的快照,而快照隔离都是拿同一个快照而已。

下图说明了以 MVCC 为基础的快照隔离机制如何运作,当一个 transaction 开始时,资料库会给定唯一的 txid (transaction ID),每笔资料会多 2 个栏位,created_bydeleted_by,当资料写入时,created_by 会记录写入的 txid ,而 deleted_by 初始是空值,当资料被删除时,资料不会真的被删掉,而是在 deleted_by 标记是哪个 txid 删除,往後垃圾收集器会定期去清除无 transaction 在用且 deleted_by 有值的快照资料。

下图的 txid 13 在更新 Account 1 的金额为 600 时,就会看到 500 那笔被标记被 tx id 13 删除,然後同时建立一笔 created_by = 13 的资料,然後 txid 13 在更新 Account 2 的资料时亦同;txid 12 查询时,因为 txid 13 是比较晚开始的 transaction,所以任何 txid 13 的写入都会被忽略,所以 txid 12 只会查到符合一致性原则的快照资料。

一致性快照的可视化规则

简单来说,一个物件要可视必须符合以下 2 个条件:

  1. 当读取者的 transaction 开始时,物件已被建立且已被其他 transaction commit。
  2. 该物件未被标记成已删除(图 7-7 的例子为 deleted_by 有值),或者当读取者的 transaction 开始时,物件已被标记删但还没 commit。

所以啦,若有个超长时间的 transaction 在执行,只要多付出一点点的 overhead,该 transaction 不用担心 read skew 的问题。

作者的抱怨:快照隔离在 Oracle 称为 Serializable ,而在 PostgreSQL 和 MySQL 称为 repeatable read ,他认为 SQL 标准里的隔离等级有瑕疵、暧昧不清且不精准的,所以一个名词可以有很多不同的意思。


read skew 解决了,明天就要来谈谈 write skew 啦!


<<:  铁人赛 Day4 -- 一定要知道的 CSS (一)

>>:  Rails has_many

[Day - 17 ] - Spring 导入选择器原理与开发

Abstract 我们前面已经讨论了相当多种取得Bean的方法,如:自动注入(@Autowired、...

DAY 01 动机与LINE Messaging API 介绍

动机 小弟在超商打工,老板有多间店的群组要管理,接收发讯息都要人工处理,所以想要做个群组机器人减少人...

Raspberry pi 的GPIO

翻开Raspberry pi 4b的datasheet "raspberry-pi-4-d...

Kotlin Android 第16天,从 0 到 ML - MVVM架构 - ViewModel

前言: 进入Android Jetpack 架构,还是要提一下什麽是MVVM,再来使用ViewMod...

D23. 学习基础C、C++语言

D23. C++介绍 C++是一种被广泛使用的电脑程序设计语言。它是一种通用程序设计语言,支援多重程...