ホームページ >データベース >mysql チュートリアル >MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC

MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC

coldplay.xixi
coldplay.xixi転載
2020-10-27 17:03:222691ブラウズ

mysql 教程MySQL 関連の項目、隔壁および MVCC。

MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC

MySQL シリーズの 4 番目のセクション。主な内容は事であり、事の ACID 特性、隔離段階、謄本、複製不可能、幻覚の理解、および多バージョンおよび発行制御 (MVCC) などの内容が含まれます。

# 事(トランザクション) は、分割不可能な原子性オペレーション セットを常に実行し、常に実行しないようにすることができます。

本明細書において、特に断りのない限り、使用するデータテーブルおよびデータは次のとおりです。 ACID 四大特性

# まず最初に理解すべきは、ACID 四大特性、すなわち原子性 (Atomicity)、均一性 (Consistency)、遮断性 (Isolation)、持久性 (Durability) であり、これもまた重要なことです。 4 つの基本要素。我々の残金はすべて100元):

我の残金

我の残金100元

100元開始移行

    顧客の残りの約
  1. 顧客の約 100 元
  2. 1.1 原子性 (原子性)
  3. 事の原子性とは、次のことを指します。ディジットは再分割不可能な最小操作単位である必要があり、1 つのディジット内の操作が必ず成功する必要があり、必ず失敗する必要があり、1 つのジグ内の一部の操作のみを実行するという状況は存在しません。原子性は、この 5 つのステップをすべて実行することを要求しており、すべてが実行されなければ、私のお金 100 単位が存在する可能性はありますが、転送されるお金 100 単位は存在しません。 (一貫性)
  4. 事の一貫性とは、データ全体が一つの一貫性状態から別の一貫性状態に移行すること、一貫性側がデータの可視性であること、データの中間状態がそれ以外に不可視であることを意味します。
  5. 同时,事务的一致性要求符合开发人员定义的约束,如金额大于0、身高大于0等。

    在上述的转账场景中,一致性能够保证最终执行完整个转账操作后,我账户的扣款金额与你账户到账金额是一致的,同时如果我和你的账户余额不满足金额的约束(如小于0),整个事务会回滚。

    1.3 隔离性(Isolation)

    事务的隔离性是指:在一次状态转换过程中不会受到其他状态转换的影响。

    假设我和你都有100元,我发起两次转账,转账金额都是50元,下面使用伪代码来表示的操作步骤:

    1. 查询我的账户余额 read my
    2. 我的账户扣款50元 my=my-50
    3. 50元开始转移
    4. 查询你的账户余额 read yours
    5. 你的账户到账50元 yours=yours+50

    如果未保证隔离性就可能发生下面的情况:

    时刻 第一次转账 第二次转账 我的账户余额 你的账户余额
    1 read my(100)
    my=100 yours=100
    2
    read my(100) my=100 yours=100
    3 my=my-50=100-50=50
    my=50 yours=100
    4 read yours(100) my=my-50=100-50=50 my=50 yours=100
    5 yours=yours+50=100+50=150
    my=50 yours=150
    6
    read yours(150) my=50 yours=150
    7
    yours=yours+50=150+50=200 my=50 yours=200
    7 end end my=50 yours=200

    两次转账后,最终的结果是我的账户余额为50元,你的账户余额为200元,这显然是不对的。

    而如果在保证事务隔离性的情况下,就不会发生上面的情况,损失的只是一定程度上的一致性。

    1.4 持久性(Durability)

    事务的持久性是指:事务在提交以后,它所做的修改就会被永久保存到数据库。

    在上述的转账场景中,持久性就保证了在转账成功之后,我的账户余额为0,你的账户余额为200。

    2. 自动提交与隐式提交

    2.1 自动提交

    在 MySQL 中,我们可以通过 begin 或 start transaction 来开启事务,通过 commit 来关闭事务,如果 SQL 语句中没有这两个命令,默认情况下每一条 SQL 都是一个独立的事务,在执行完成后自动提交

    比如:

    update user set name='重塑' where id=1;复制代码

    假设我只执行这一条更新语句,在我关闭 MySQL 客户端然后重新打开一个新的客户端后,可以看到 user 表中的 name 字段值全变成了「重塑」,这也印证了这条更新语句在执行后已被自动提交。

    自动提交是 MySQL 的一个默认属性,可以通过 SHOW VARIABLES LIKE 'autocommit' 语句来查看,当它的值为 ON 时,就代表开启事务的自动提交。

    mysql> SHOW VARIABLES LIKE 'autocommit';
    +---------------+-------+| Variable_name | Value |
    +---------------+-------+| autocommit    | ON    |
    +---------------+-------+1 row in set (0.00 sec)复制代码

    我们可以通过 SET autocommit = OFF 来关闭事务的自动提交。

    2.2 隐式提交

    然而,即便我们已经将 autocommit 变量的值改为 OFF 关闭事务自动提交了,在执行某些 SQL 语句的时候,MySQL 还是会将事务自动提交掉,这被称为隐式提交

    会触发隐式提交的 SQL 语句有:

  • DDL(Data definition language,数据定义语言),如 create, drop, alter, truncate
  • 修改 MySQL 自带表数据的语句,如 create/drop user, grant, set password
  • 在一个事务中,开启一个新的事务,会隐式提交上一个事务,如:
时刻 事务A 事务B
1 begin;
2 update user set name='重塑' where id=1;
3
select name from user where id=1;(N1)
4 begin;
5
select name from user where id=1;(N2)

トランザクション B には 2 つのクエリ文 N1 と N2 があります。実行結果は N1=hedgehog と N2=reshape であり、証明できます。

  • 他にもいくつかの管理ステートメントがあるため、一例を説明しません。

3. 分離レベル

トランザクションの分離レベルは、トランザクション内およびトランザクション間のトランザクションで行われた変更の可視性を指定します。通常、分離レベルが低いほど、同時実行性が高まり、システムのオーバーヘッドが低くなります。

SQL 標準では、Read Uncommitted、Read Committed、Repeatable Read、Serializable (Serializable) という 4 つのトランザクション分離レベルが定義されています。

##これら 4 つの分離レベルとそれぞれの現象を詳しく説明するために、2 つのトランザクションが実行されようとしていて、実行内容が次のとおりであると仮定します。

#時間 1234##5##コミット;id=1 のユーザーから名前を選択;(N2)commit;id=1 のユーザーから名前を選択;(N3) トランザクション A とトランザクション B の実行中に、3 つのクエリ N1、N2、および N3 が存在します。各分離レベルでは、その値がは異なります。以下で個別に説明します。 3.1 コミットされていない読み取り
トランザクション A トランザクション B
begin;

開始;

ユーザー セット名を更新 = 'reshape' where id=1;
ユーザーから名前を選択 ここでid=1; (N1)

6

7

8

コミットされていない読み取り分離レベルでは、

トランザクション内の変更は、コミットされていない場合でも他のトランザクションに表示されます

上記のシナリオでは、データベースの分離レベルがコミットされていない状態で読み取られる場合、トランザクション A はコミットされていないトランザクション B の変更されたデータを読み取ることができるため、時間 3 でのトランザクション B の変更はトランザクションに表示されます。 A、つまり、N1=形状変更、N2=形状変更、N3=形状変更。 3.2 コミットされた読み取り

コミットされた読み取り分離レベルでは、

トランザクション内の変更は、コミットされるまで他のトランザクションには表示されません

上記のシナリオでは、データベースの分離レベルが読み取りコミットされている場合、トランザクション A はトランザクション B が送信された後にのみデータを読み取ることができるため、つまり、時刻 3 でのトランザクション B の変更は表示されません。トランザクション A、N2 へ のクエリはトランザクション B が送信された後であるため、トランザクション A には表示されます。したがって、N1=ハリネズミ、N2=再発明、N3=再発明となります。 3.3 反復可能読み取り

反復可能読み取りは、MySQL のデフォルトのトランザクション分離レベル

です。反復可能な読み取り分離レベルでは、

同じレコードがトランザクション内で複数回クエリされ、結果は常に一貫しています

上記のシナリオでは、データベースの分離レベルが反復読み取りである場合、クエリ N1 と N2 はトランザクション内にあるため、それらの値は両方とも「ハリネズミ」であり、N3 はトランザクション後に実行されます。 A が送信されます。実行されたクエリでは、トランザクション B への変更が表示されるため、N3 = 再形成されます。 3.4 シリアル化可能

シリアル化可能分離レベルでは、

トランザクションはシリアルに実行され、読み取りにより読み取りロックが増加し、書き込みにより書き込みロックが増加します。

、トランザクションは同時に実行されません。 , したがって、例外は発生しません。

上記のシナリオでは、データベースの分離レベルがシリアル化可能である場合、トランザクション A が最初にオープンされ、トランザクション B がオープンされるとブロックされます。トランザクション B は、トランザクション A が送信されるまでオープンされないため、N1 = ハリネズミ、N2=ハリネズミ。 N3 のクエリはトランザクション B が送信された後に実行されます (トランザクション B が最初にブロックされ、実行順序は N3 クエリ ステートメントの前になります)。したがって、N3=reshape になります。 4. 分離レベルによって引き起こされる問題

異なるトランザクション分離レベルでは、トランザクションが同時に実行されると、ダーティ リード (Dirty Read)、非反復読み取り (以下では、さまざまな例を使用して、これらの問題について詳しく説明します。

4.1 ダーティ リード

ダーティ リード

(ダーティ リード) は、トランザクションが、コミットされていない別のトランザクションによって変更されたデータを読み取ることができることを意味します。

分離レベルがコミットされていない状態で読み取られると仮定して、次のケースを見てください:

TimeTransaction A1begin;#begin;ユーザー セット名を更新= 「Re Plastic」 (id=1;ユーザーからの名前を選択 (id=1);(N1)ロールバック;名前を選択ユーザーから id=1;(N2)commit;##

read uncommitted の分離レベルでは、N1 の値は「reshape」ですが、トランザクション B のロールバックにより、N2 の値は「hedgehog」になります。ここ N1 でダーティ リードが発生しました。明らかに、N1 でのクエリ結果はダーティ データであり、通常のビジネスに影響を及ぼします。

ダーティ読み取りは、読み取り非コミット分離レベルで発生します。

4.2 Non-Repeatable Read

Non-Repeatable Read (Non-Repeatable Read) は、同じクエリを 2 回実行すると異なる結果が生じる可能性があることを意味します。

#分離レベルを導入するときに AB トランザクションのケースを引き続き使用し、分離レベルが読み取りコミットであると想定します:

Transaction B

2

3

4

5

6
##7
#Time1#23456id=1 のユーザーから名前を選択;(N2)##78##読み取りコミット分離レベルでは、トランザクションは他のトランザクションによって送信されたデータを読み取ることができます。上記の場合、結果は N1=hedgehog、N2=reshape、N3=reshape です。トランザクション A には、2 つの同一のクエリ N1 と N2 がありますが、これら 2 つのクエリの結果は同じではありません。この問題が発生しました。読み取れません。繰り返し。
トランザクション A トランザクション B
begin;

開始;

ユーザーセット名を更新 = 'reshape' where id=1;
select name from user where id=1;(N1)

コミット;

コミット;
id=1 のユーザーから名前を選択;(N3)

非反復読み取りは、非コミット読み取りおよびコミット読み取りの分離レベルで発生します。

4.3 Phantom Read

Phantom Read

(ファントム読み取り) とは、トランザクションが特定の範囲のレコードを読み取るときに、別のトランザクション Insert newこの範囲のレコード。前のトランザクションがこの範囲のレコードを再度読み取ると、この新しいレコードが読み取られます。 現時点で分離レベルが反復読み取り可能であると仮定して、次のケースを見てください:

Time1 ##2 ユーザーから名前を選択;(N1)begin;ユーザー値に挿入(2, '五条人');コミット;ユーザーから名前を選択; (N2 )更新するユーザーから名前を選択;(N3)コミット;
Transaction A トランザクション B
begin;

##3

4

5

6
##7
8

トランザクション A には 3 つのクエリがあります。N1 と N2 の間で、トランザクション B は挿入ステートメントを実行し、送信しました。N3 のクエリは for update を使用しました。

N1 での結果は明らかに単なる「ハリネズミ」です。トランザクション A がトランザクション B より前にオープンされているため、N2 での結果も「ハリネズミ」です。N3 での結果は、理論的には反復読み取り分離レベルにあります。 N2 には「ハリネズミ」しかないはずですが、実際には N2 の結果は「ハリネズミ」と「五條男」となり、ファントムリーディングが発生します。

これは非常に奇妙です。反復可能な読み取りの分離レベルにより、トランザクション内で同じレコードが複数回クエリされ、結果が常に一貫していることが保証されるということではないでしょうか?この結果は、反復読み取りの定義を満たしていません。

実際、Repeatable Read の分離レベルでは、current read が使用されると、ファントム読み取りが発生する可能性があります。

現在の読み取りとスナップショットの読み取りについては、後でトランザクションと MVCC の実装原則を紹介するときに説明しますが、先に結論を述べます。

ファントム読み取りは、非コミット読み取り、コミット読み取り、反復読み取りの分離レベルで発生します。

ここで特別な注意が必要なのは、: ファントム読み取りと非反復読み取りはどちらも、トランザクション内の同じクエリ ステートメントの結果は異なるが、ファントムであることを意味します。 read は、他のトランザクションによって新しく挿入されたデータ (insert) または他のトランザクションによって削除されたデータ (delete) のクエリに焦点を当てますが、non-repeatable read はより広い範囲を対象とします。 -反復可能読み取りですが、一般的には非反復可能読み取りを考えます。他のトランザクションによるデータの更新に重点を置きます。

4.4 概要

上記の説明を通じて、4 つの分離レベルの概念とそれぞれが直面する問題についてはすでに理解しました。トランザクションの分離レベルが高いほど、分離は強化されます。遭遇する問題も少なくなります。しかし同時に、分離レベルが高くなるほど、同時実行機能は弱くなります。

##次の表は、分離レベルの概念と、さまざまな分離レベルで発生する可能性がある問題をまとめたものです。

#分離レベル##送信されたリード√√√トランザクション内の変更は、コミットされていない場合でも他のトランザクションに表示されます未コミットの読み取り√トランザクション内の変更は、送信された後に他のトランザクションにのみ表示されます反復読み取り##√#シリアル化可能

5. MVCC

MVCC(Multi-Version Concurrency Control)即多版本并发控制,这是 MySQL 为了提高数据库并发性能而实现的。它可以在并发读写数据库时,保证不同事务的读-写操作并发执行,同时也能解决脏读、不可重复读、幻读等事务隔离问题。

在前文讨论幻读的时候提到过当前读的概念,正是由于当前读,才会在可重复读的隔离级别下也会发生幻读的情况。

在解释可重复读隔离级别下发生幻读的原因之前,首先介绍 MVCC 的实现原理。

5.1 MVCC 的实现原理

首先我们需要知道,InnoDB 的数据页中每一行的数据是有隐藏字段的:

  • DB_ROW_ID: 隐式主键,若表结构中未定义主键,InnoDB 会自动生成该字段作为表的主键
  • DB_TRX_ID: 事务ID,代表修改此行记录的最后一次事务ID
  • DB_ROLL_PTR: 回滚指针,指向此行记录的上一个版本(上一个事务ID对应的记录)

每一条修改语句都会相应地记录一条回滚语句(undo log),如果把每一条回滚语句视为一条数据表中的记录,那么通过事务ID和回滚指针就可以将对同一行的修改记录看作一个链表,链表上的每一个节点就是一个快照版本,这就是 MVCC 中多版本的意思。

举个例子,假设对 user 表中唯一的一行「刺猬」进行多次修改。

update user set name='重塑' where id=1;update user set name='木马' where id=1;update user set name='达达' where id=1;复制代码

那么这条记录的MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC就是:

MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC

在这个MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC中,头结点就是当前记录的最新版本。DB_TRX_ID 事务ID 字段是非常重要的属性,先 Mark 一下。

除此之外,在读已提交(RC,Read Committed)和可重复读(RR,Repeatable Read)的隔离级别中,事务在启动的时候会创建一个读视图(Read View),用它来记录当前系统的活跃事务信息,通过读视图来进行本事务之间的可见性判断

在读视图中有两个重要的属性:

  • 当前事务ID:表示生成读视图的事务的事务ID
  • 事务ID列表:表示在生成读视图时,当前系统中活跃着的事务ID列表
  • 最小事务ID:表示在生成读视图时,当前系统中活跃着的最小事务ID
  • 下一个事务ID:表示在生成读视图时,系统应该分配给下一个事务的事务ID

需要注意下一个事务I的值,并不是事务ID列表中的最大值+1,而是当前系统中已存在过的事务的最大值+1。例如当前数据库中活跃的事务有(1,2),此时事务2提交,同时又开启了新事务,在生成的读视图中,下一个事务ID的值为3。

我们通过将MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC与读视图两者结合起来,来进行并发事务间可见性的判断,判断规则如下(假设现在要判断事务A是否可以访问到事务B的修改记录):

  • 若事务B的当前事务ID小于事务A的最小事务ID的值,代表事务B是在事务A生成读视图之前就已经提交了的,所以事务B对于事务A来说是可见的。
  • 若事务B的当前事务ID大于或等于事务A下一个事务ID的值,代表事务B是在事务A生成读视图之后才开启,所以事务B对于事务A来说是不可见的。
  • 若事务B的当前事务ID在事务A的最小事务ID下一个事务ID之间(左闭右开,[最小事务ID, 下一个事务ID)),需要分两种情况讨论:
    • 若事务B的当前事务ID在事务A的事务ID列表中,代表创建事务A时事务B还是活跃的,未提交,所以事务B对于事务A来说是不可见的。
    • 若事务B的当前事务ID不在事务A的事务ID列表中,代表创建事务A时事务B已经提交,所以事务B对于事务A来说是可见的。

如果事务B对于事务A来说是不可见的,就需要顺着修改记录的MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC,从回滚指针开始往前遍历,直到找到第一个对于事务A来说是可见的事务ID,或者遍历完MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC也未找到(表示这条记录对事务A不可见)。

这就是 MVCC 的实现原理。

5.2 読み取りビューの作成タイミング

ここで注意する必要があるのは、読み取りビューの作成タイミングです。上記の説明で、トランザクションが実行されることはすでにわかっています。開始時に を作成します。Read View (Read View) トランザクションを開始するには 2 つの方法があります。1 つは begin/starttransaction、もう 1 つは starttransaction一貫性のあるスナップショットを使用して、次の 2 つを使用します。 メソッドでトランザクションを開くには、読み取りビューを作成するタイミングも異なります。

  • トランザクションが begin/ で開かれる場合starttransaction メソッドを実行すると、読み取りビューは最初のスナップショット読み取りステートメントを実行します。
  • starttransactionwithconsistentsnapshot でトランザクションを開始すると、同時に読み取りビューが作成されます。 time

5.3 MVCC の実行プロセス

MVCC の実行プロセスを詳しく説明するために、現在 2 つのトランザクション (トランザクション分離レベル) が存在すると仮定した例を以下に示します。は MySQL のデフォルトの反復読み取りです):

ここで注意する必要があるのは トランザクションの開始タイミング です。上記の説明で、トランザクションによって Read が作成されることはすでにわかっています。開始時に表示 (ビューの読み取り) を実行します。トランザクションを開始するには 2 つの方法があります。1 つは begin/starttransaction、2 つ目は 一貫性のあるスナップショットを使用してトランザクションを開始する、これら 2 つのメソッドでトランザクションを開始する場合、読み取りビューを作成するタイミングも異なります。

  • If トランザクションが begin/starttransaction メソッドで開始される場合、読み取りビューは、最初のスナップショット読み取りステートメントが実行されるときに作成されます。
  • 一貫性のあるスナップショットを使用した start トランザクション メソッド トランザクションで開始された場合、読み取りビューは同時に作成されます
ダーティ リード 繰り返し不可能なリード ファントム リード コンセプト



1 つのトランザクション内の複数のクエリ同じレコード、結果は常に一貫しています


#トランザクションはシリアルに実行され、読み取りでは読み取りロックが追加され、書き込みでは書き込みロックが追加されます

#時間トランザクションAトランザクションB1一貫性のあるスナップショットでトランザクションを開始;2一貫性のあるスナップショットでトランザクションを開始;##3##4id=1 のユーザーから名前を選択;(N1) 56ID=1 のユーザーから名前を選択;(N2)コミット;



ユーザー セット名 = 'Reshape' (id=1) を更新;

commit;

#7

次に、上記のバージョン チェーンと 2 つのトランザクションが開始されたときの読み取りビューに基づいて、MVCC の実行プロセスを分析します。

MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC

#上図はトランザクションを2つ開始した場合の読み込みビューで、トランザクションBのupdate文を実行すると、行id=1のバージョンチェーンは以下のようになります。

mvcc2-MySQL についての私の理解パート 4: トランザクション、分離レベル、MVCC

まず、N1 のクエリ ステートメントを見てみましょう。トランザクション B の現在の

トランザクション ID は 2 で、その値は ## に等しいです。 # トランザクション A の次。トランザクション ID。したがって、上で説明した可視性の判断によれば、トランザクション B はトランザクション A には見えず、現在の行のバージョン チェーンに沿ってオンラインで取得する必要があります。 そこで、バージョン チェーンを

DB_TRX_ID=1

トランザクション ID=1 の履歴バージョンにたどりました。これはたまたまトランザクション A のトランザクション ID 値と同じであり、これはトランザクション A のバージョンです。トランザクション A が開始されたときの行。もちろんこのバージョンはトランザクション A に表示されるため、行 id=1 の name='hedgehog'、つまり最後の N1=hedgehog が読み取られます。 N2 のクエリ ステートメントを見ると、この時点でトランザクション B が送信されており、現在のバージョンのトランザクション ID が ## に等しいため、バージョン チェーンは依然として上図のとおりです。トランザクション A の読み取りビュー内の #次のトランザクション ID

したがって、レコードの現在のバージョンはトランザクション A には見えないため、同じ N2=hedgehog になります。

ここで、例のトランザクション A の time 4 ステートメントが行の更新ステートメントに変更された場合、トランザクション A は更新を実行する前にトランザクション B が送信されるのを待つことに注意してください。これは、トランザクション B がコミットされていない、つまり行 id=1 に対するトランザクション B の書き込みロックが解放されておらず、トランザクション A も行を更新する必要があるため、最新バージョン (現在の読み取り) を更新する必要があるためです。トランザクション A がブロックされている場合は、更新ステートメントの実行を続行する前に、行に対するトランザクション B の書き込みロックが解放されるまで待つ必要があります。

5.4 RC と RR の間で読み取りビューを生成するタイミングの比較

上記で説明した MVCC 実行プロセスはすべて、Repeatable Read (RR、Repeatable Read) 分離レベル用です。 Read Committed (RC、Read Committed) レベルについてはどうですか?

Read Committed 分離レベルでの反復不可能な読み取りの状況についてはすでに説明しましたが、ここでは例を示さず、結論だけを直接示します。

Repeatable Read (RR、Repeatable Read) 分離レベルで Read View (Read View) を生成するタイミングは、トランザクションの開始時です。 Read Committed) 分離レベルでの読み取りビュー (Read View) を生成するタイミングは、各ステートメントの実行前です。

  • 上記の MVCC 実行処理の例の場合、分離レベルがRead Committed (RC、Read Committed ):
  • N1 のクエリ ステートメント。トランザクション B がまだ送信されていないため、トランザクション A の表示されているバージョンはトランザクション ID=1 のバージョンのままです。 N1=Hedgehog

N2 クエリ ステートメントでは、トランザクション B が送信されました。N2 のクエリ ステートメントが実行されると、読み取りビューも生成されます。現在のトランザクション ID=3 で、バージョン チェーン内にあります。レコードの現在のバージョンのトランザクション ID

DB_TRX_ID=2
    は、N2 クエリ ステートメントのトランザクション ID の前に表示されるため、N2=reshape
  • 5.5 現在の読み取りとスナップショットの読み取り
現在の読み取り

: レコードの最新バージョンを読み取ります

  • スナップショット読み取り: レコードを読み取るとき、トランザクションに表示されるバージョンのレコードは特定のルールに従って読み取られます。
  • 5.6 ファントム読み取りが発生する反復可能な理由MVCC を理解した後、反復可能な読み取り分離レベルでファントム読み取りが発生する理由を見てみましょう。 。上で述べたように、再現可能な読み取りの分離レベルでファントム読み取りが発生するのはまさに現在の読み取りのためです。

#時間

トランザクション Aトランザクション Bbegin;#3開始;4# # commit;#6ユーザーから名前を選択;(N2)# # 7##8コミット;
#1
#2 ユーザーから名前を選択;(N1)


##insert into user names(2, '五条人');
5

更新するユーザーから名前を選択;(N3)
# ##################################

N1 と N2 でのクエリは、それらがすべて「ハリネズミ」であることを非常に明確に示していたはずです。 N3 で使用されるクエリ ステートメントは for update です。これをクエリに使用すると、ターゲット レコードに「行レベルのロック」が追加されます。行レベルのロックの意味については後で説明します。 更新用に知っておく必要があるターゲット レコードをロックできることだけです。

ロックは当然、他の人が変更できないようにするためのものなので、当然のことながら、ロックされるのはレコードの最新バージョンです。したがって、for update を使用してクエリを実行する場合、current read を使用してターゲット レコードの最新バージョンを読み取ることになるため、N3 のクエリ ステートメントはトランザクション B の元のバージョンを変更します。トランザクション A には見えないレコードも照会され、ファントム読み取りが発生します。

現在の読み取りを使用するステートメントは次のとおりです:

  • select ... for update
  • select ... 共有モードでロック (共有読み取りロック)
  • update ...
  • insert ...
  • delete ...

6. 過去を振り返り、新しいことを学ぶ

  1. 問題 ACID の 4 つの主要な特徴
  2. 自動送信と暗黙的送信 (暗黙的に送信されたステートメント)
  3. トランザクションの分離レベル
  4. 各分離レベルで考えられる問題トランザクションの数
  5. MVCC の実装原理とプロセス
  6. 読み取りビューを生成するための RC と RR のタイミング

その他の関連する無料学習推奨事項:mysql チュートリアル #(ビデオ)

以上がMySQL についての私の理解パート 4: トランザクション、分離レベル、MVCCの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.imで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。