MySQL ファントムリードとその排除方法の詳細な説明

MySQL ファントムリードとその排除方法の詳細な説明

これは、データベース分離レベルに関するポピュラーサイエンスの記事です。データベースにおける有名なファントム リード現象を理解することを目的としています。トピックに焦点を当てるため、ダーティ リードと非反復リードについては説明しません。

トランザクション分離レベル

MySQL には 4 つのトランザクション分離レベルがあります。

読み取り非コミット: ダーティ リード、非反復読み取り、およびファントム リードの問題が存在します。読み取りコミット: ダーティ リードはありませんが、非反復読み取りとファントム リードの問題が存在します。反復読み取り: ダーティ リード、非反復読み取りの問題はありませんが、ファントム リードの問題が存在します。シリアル化: ダーティ リード、非反復読み取り、およびファントム リードの問題を解決しますが、実行は完全にシリアルであり、パフォーマンスは最も低くなります。

ファントムリーディングとは何ですか?

ファントム リードに関する誤った理解: ファントム リードとは、トランザクション A が 2 つの選択操作を実行して異なるデータ セットを取得することを意味します。つまり、選択 1 では 10 個のレコードが取得され、選択 2 では 11 個のレコードが取得されます。これは実際にはファントム リードではなく、非反復読み取りの一種であり、RU RC レベルでのみ発生し、MySQL のデフォルトの RR 分離レベルでは発生しません。

ファントムリーディングについての私の理解は次のとおりです。

ファントム リードは、トランザクション内の複数の読み取りから取得された結果セットが異なることを意味するものではありません。ファントム リードに関してより重要なのは、特定の選択操作から取得された結果セットによって表されるデータ状態が、後続のビジネス操作をサポートできないことです。具体的には、選択したレコードが存在せず、このレコードを挿入しようとしているが、挿入を実行すると、このレコードがすでに存在し、挿入できないことがわかり、まるで錯覚のようだ。

例を挙げると理解しやすくなるかもしれません:

mysql> テーブル user\G の作成を表示します
************************** 1. 行 ****************************
 テーブル: ユーザー
テーブルの作成: CREATE TABLE `user` (
 `id` int(11) NULLではない、
 `name` varchar(32) デフォルト NULL,
 主キー (`id`)
) エンジン=InnoDB デフォルト文字セット=utf8

2 つのトランザクション T1 と T2 をそれぞれ開始し、分離レベルを Reaptable-Read に設定します。

T1:

mysql> グローバルトランザクション分離レベルを繰り返し読み取りに設定します。      
​
mysql> 開始します。
mysql> ユーザーから * を選択します。
mysql> ユーザー値に挿入(1、 'jeff');
エラー 1062 (23000): キー 'PRIMARY' のエントリ '1' が重複しています
​
mysql> ユーザーから * を選択します。

T2:

mysql> グローバルトランザクション分離レベルを繰り返し読み取りに設定します。      
​
mysql> 開始します。
mysql> ユーザー値に挿入(1、 'jeff');
mysql> コミット;

T1 トランザクションは、テーブル内に ID 1 のレコードがあるかどうかを確認し、ない場合はそれを挿入します。

T2 は干渉レコードを挿入し、T1 でファントム リードが発生します。

上記の例では、トランザクション T2 を実行する前にトランザクション T1 が実行されるようにする必要があります。

上記の例では、T1 で読み取られたデータ状態が後続のアクションと意味的に矛盾しているため、T1 でファントム リードが発生します。クエリを実行すると、レコードが存在しないことが明確に示されますが、挿入を実行すると、主キーが重複していることが示されます。これはファントムの出現に似ているため、ファントム リードと呼ばれます。

ファントムリードを排除する方法

MySQL には現在、ファントム リードを取り除く 2 つの方法があります。

1. 選択操作 (SELECT ... FOR UPDATE) に行 X ロックを手動で追加します。その理由は、InnoDB の行ロックがインデックスをロックするためです。現在のレコードが存在しない場合でも、現在のトランザクションはレコード ロックを取得します (レコードが存在する場合は行 X ロックが追加され、存在しない場合は次のキー ロック ギャップ X ロックが追加されます)。このようにして、他のトランザクションはこのインデックスのレコードを挿入できず、ファントム リードが排除されます。
2. 分離レベルをさらにSERIALIZABLEに上げる
効果をテストする

mysql> 開始します。
​
mysql> id = 2 の場合、user から * を選択して更新します。
mysql> ユーザー値に挿入(2、 'tony');

mysql> コミット;

T2:

mysql> 開始します。
​
mysql> ユーザー値に挿入(2、 'jimmy');
エラー 1062 (23000): キー 'PRIMARY' のエントリ '2' が重複しています

ここで、T1 が更新のためにクエリされると、インデックスは Innodb でロックされます (現在存在しない場合でも)。そのため、トランザクション T2 の挿入は、T1 がコミットされるまでブロックされます。このようにして、T1 は成功します。T1 の場合、ファントム リードは確かに排除されますが、T2 の挿入では重複した主キーが報告されますが、これも予想どおりです。

分離レベルを向上させてファントム リードを排除する別の方法については、興味のある方は自分で試してみてください。ここでは繰り返しません。システムが手動ロックを置き換える点を除けば、本質は同様です。

要約する

RR は、MySQL トランザクションのデフォルトの分離レベルです。これは、トランザクションのセキュリティとパフォーマンスの間の妥協点です。ファントム リードについて正しく理解した後、開発者は必要に応じてファントム リードを防止するかどうかを決定できます。

SERIALIZABLE は悲観的であり、ファントム リードが常に発生すると想定しているため、トランザクションに必要なリソースに自動的かつ暗黙的に排他ロックを追加します。このリソースにアクセスする他のトランザクションはブロックされ、待機状態になります。トランザクションは安全ですが、パフォーマンスを慎重に考慮する必要があります。

InnoDB ロックはインデックス用なので注意が必要です。行レコードをロックします。存在する場合は、X ロックを追加します。そうでない場合は、次のキー ロック/ギャップ ロック/ギャップ ロックを追加します。これにより、InnoDB は、トランザクションによる特定のレコードの事前占有を実現できます。トランザクションが存在する限り、他のトランザクションはそれを占有できません。ロックについては後ほど特別記事で取り上げます。

以上がMySQLファントムリードとその解消方法の詳細な説明です。MySQLファントムリードとその解消方法の詳細については、123WORDPRESS.COMの他の関連記事をご覧ください。

以下もご興味があるかもしれません:
  • MySQL トランザクション機能を使用して同時かつ安全な自動増分 ID を実装する例
  • PHP+MySQL の高同時ロックトランザクション処理問題の解決方法
  • MySQL の繰り返し読み取りレベルでファントム読み取りを解決できますか?
  • MySQLがファントムリードを解決する方法の詳細な説明
  • MySQL トランザクション同時実行問題の解決
  • MySQL シリーズ 10 同時実行制御を実装するための MySQL トランザクション分離
  • MySQL のファントムリード問題を解決する方法
  • mysql+mybatisはストアドプロシージャ+トランザクション+複数同時シリアル番号取得を実装します
  • Mysql トランザクションにおける同時ダーティ リード + 非反復リード + ファントム リードの詳細な説明

<<:  HTMLハイパーリンクタグAのTARGET属性の詳細な説明

>>:  Docker tomcatのメモリサイズを設定する方法

推薦する

Vue は div の高さをドラッグ可能にします

この記事では、divのドラッグ可能な高さを実現するためのVueの具体的なコードを参考までに共有します...

ウェブ標準学習リソースの素晴らしいコレクション

これらの仕様は、下位互換性のあるドキュメントを Web 上で公開し、できるだけ幅広いユーザーがアクセ...

MySQLインデックスを追加する3つの原則を簡単に理解する

1. インデックスの重要性インデックスは、列に特定の値を持つ行をすばやく見つけるために使用されます。...

MySQL の current_timestamp の落とし穴とその解決策を共有する

目次MySQL の current_timestamp の落とし穴エラーを報告する私の解決策mysq...

Centos7 での DNS サーバーの構築の概要

目次1. プロジェクト環境: 2: DNSサーバーの設定i: 前方解析を構成する: ii: 逆解像度...

CentOS7.8 に mysql 8.0.20 をインストールするための詳細なチュートリアル

1. MySQLソフトウェアをインストールするMySQL 公式 Yum リポジトリ、MySQL バー...

Vue 監視プロパティと計算プロパティ

目次1. 監視プロパティを監視する1. ショッピングカート2. すべて選択し、すべて選択解除する2....

a タグをクリックして入力ファイルのアップロードダイアログボックスを表示する方法

htmlコードをコピーコードは次のとおりです。 <SPAN class=tag><...

Linux 負荷分散 LVS の詳細な理解

目次1. LVS 負荷分散2. 負荷分散LVSの基本紹介3. LVSアーキテクチャ3.1 ロードバラ...

Mysql でサーバーの UUID を変更する方法

問題の原因:スレーブサーバーがクローンマスターサーバーである場合、server-uuidの値は同じで...

Windows10でのMySQL 5.7.21のインストールと設定のチュートリアル

この記事では、MySQL 5.7.21 のインストールと設定方法を記録し、皆様と共有します。 1. ...

CSS 擬似要素::マーカーの詳細な説明

この記事では、CSS ::markerの興味深い疑似要素を紹介します。これを使用すると、テキスト番号...

Docker Composeでコンテナ管理の問題を解決する

Docker の設計では、コンテナは 1 つのアプリケーションのみを実行します。しかし、現在のアプリ...

CSS3アニメーションとHTML5の新機能の詳しい説明

1. CSS3アニメーション☺CSS3 アニメーションは、JavaScript を介して要素のスタイ...

システムメンテナンスページにリダイレクトするように nginx を設定する

先週末、兄弟プロジェクトはより良いサービスを提供するためにサーバーを拡張する準備をしていました。兄弟...