15
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ダーティリード、ノンリピータブルリード、ファントムリードを実演する

Posted at

はじめに

この記事ではデータベースの読み込み時に起こる3つの現象、ダーティリード、ノンリピータブルリード、ファントムリードについて実演することで理解を深めていこうと思います。

この記事の対象者

  • データベースを使った開発を行っている人
  • データベーススペシャリストの資格を目指している人

実演環境

$ mysql --version
mysql  Ver 15.1 Distrib 10.5.4-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2

実演用のテーブルおよびデータ

MariaDB [sample]> desc users;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(40) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

MariaDB [sample]> select * from users;
+----+------+
| id | name |
+----+------+
|  1 | Adam |
+----+------+

ダーティリード

説明

あるトランザクションがコミットされていない状態でも、別のトランザクションから変更内容を読み込めてしまう現象のことです。

実演

以下、ダーティリードを起こすために、トランザクションBのトランザクション分離レベルをREAD-UNCOMMITTEDに設定しています。

set session transaction isolation level read uncommitted;
Transaction B > select @@tx_isolation;
+------------------+
| @@tx_isolation   |
+------------------+
| READ-UNCOMMITTED |
+------------------+
  1. トランザクションAを開始する
    スクリーンショット 2021-06-06 12.16.03.png

  2. トランザクションBを開始する
    image.png

  3. トランザクションAにてusersテーブルを更新する
    image.png

  4. トランザクションBにてusersテーブルを確認する
    image.png

まだ、トランザクションAはコミットしていませんが、更新したデータをトランザクションBから読み込めてしまっています。

ノンリピータブルリード

説明

あるトランザクションが2回同じデータを読み込む際に、1回目の読み込みと2回目の読み込みで値が異なってしまう現象のことです。

実演

以下、ノンリピータブルリードを起こすために、トランザクションBのトランザクション分離レベルをREAD-COMMITTEDに設定しています。

set session transaction isolation level read committed;
Transaction B > select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
  1. トランザクションAを開始する
    image.png

  2. トランザクションBを開始する
    image.png

  3. トランザクションBにてusersテーブルを確認する
    image.png

  4. トランザクションAにてusersテーブルを更新する
    image.png

  5. トランザクションAをコミットする
    image.png

  6. トランザクションBにて再度usersテーブルを確認する
    image.png

トランザクションBにて1回目の読み込み(手順3)と2回目の読み込み(手順6)の内容が異なってしまっています。

ファントムリード

説明

あるトランザクションが2回同じデータを読み込む際に、2回目の読み込みで1回目には存在しなかったデータが読み込めてしまう現象のことです。

実演

以下、ファントムリードを起こすために、トランザクションBのトランザクション分離レベルをREAD-COMMITTEDに設定しています。
(詳しくは調べていませんが、MySQL(InnoDB)だとREPEATABLE-READではファントムリードが起きないようですので、READ-COMMITTEDで確認します。)

set session transaction isolation level read committed;
Transaction B > select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
  1. トランザクションAを開始する
    image.png

  2. トランザクションBを開始する
    image.png

  3. トランザクションBにてusersテーブルを確認する
    image.png

  4. トランザクションAにてusersテーブルにレコードを追加する
    image.png

  5. トランザクションAをコミットする
    image.png

  6. トランザクションBにて再度usersテーブルを確認する
    image.png

トランザクションBにて1回目の読み込み(手順3)には存在しなかったレコードが2回目の読み込み(手順6)で読み込めてしまっています。

トランザクション分離レベルごとでの現象確認

以上、3つの現象について実演してきたわけですが、これらの現象のどれが起きるかはトランザクション分離レベルによって決まります。
ただし、MySQL(InnoDB)の場合、REPEATABLE-READでのファントムリードは起きないなど、データベースによって異なる場合もあるようですので、注意が必要です。

分離レベル ダーティリード ノンリピータブルリード ファントムリード
READ-UNCOMMITTED
READ-COMMITTED -
REPEATABLE-READ - -
SERIALIZABLE - - -

まとめ

この記事ではダーティリード、ノンリピータブルリード、ファントムリードを実演することで、それらの現象の理解を深めました。

私の経験上、業務の中でこれらの現象を意識して作業したということはほぼなかったと思いますが、データベースを使った開発を行う以上、トランザクション分離レベルによってはこういった現象が起きるということだけでも知っておくことは重要かと思います。

それではまた。

TomoProg

15
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?