序文データベース トランザクションに関して言えば、トランザクションの ACID 特性、分離レベル、解決される問題 (ダーティ リード、非反復読み取り、ファントム リード) など、トランザクションに関連する多くの知識が誰の頭にもすぐに浮かびますが、これらのトランザクション特性がどのように実装されているか、また 4 つの分離レベルがなぜあるのかを実際に理解している人はほとんどいないでしょう。 今日はまず、MySQL におけるトランザクション分離の実装原理について説明し、他の機能の実装原理を分析する記事を引き続き公開していきます。 もちろん、MySQL は広範かつ奥深いため、この記事で省略される部分があることは避けられません。批判や訂正は大歓迎です。 例示するMySQL のトランザクション実装ロジックはエンジン層にあり、すべてのエンジンがトランザクションをサポートしているわけではありません。次の手順は InnoDB エンジンに基づいています。 意味分離とは、異なるトランザクションが次々に送信され、実行された後、最終結果がシリアルになることを意味します。つまり、トランザクションの場合、実行中に認識されるデータの変更は、そのトランザクション自体の操作によって発生したものだけであり、他のトランザクションによって発生したデータの変更は発生しないはずです。 分離により、同時トランザクションから発生する問題が解決されます。 標準SQL分離レベル分離を実装する最も簡単な方法は、各トランザクションを順番に実行することです。前のトランザクションが完了していない場合、後続のトランザクションは待機します。しかし、この実装方法は明らかに並行処理効率が低く、実際の環境での使用には適していません。 上記の問題を解決し、さまざまなレベルの同時実行制御を実現するために、SQL 標準の設定者は、コミットされていない読み取り、コミットされた読み取り、繰り返し読み取り、およびシリアル化可能な読み取りという異なる分離レベルを提案しました。最も高い分離レベルはシリアル読み取りです。他の分離レベルでは、トランザクションが同時に実行されるため、多少の問題が許容されます。以下のマトリックスを参照してください。
MySQL の InnoDB エンジンは、コミット読み取りレベルで MVCC を通じて非反復読み取りの問題を解決し、繰り返し読み取りレベルでギャップ ロックを通じてファントム読み取りの問題を解決します。詳細については、以下の分析を参照してください。 実施原則標準SQLトランザクション分離レベルの実装原則上記で遭遇した問題は、実際には同時トランザクションにおける制御の問題です。同時トランザクションを解決する最も一般的な方法は、悲観的同時実行制御 (つまり、データベースのロック) です。標準 SQL トランザクション分離レベルの実装はロックに依存します。どのように実装されるかを見てみましょう。
ロックのみを使用して分離レベル制御を実装すると、頻繁なロックとロック解除が必要になり、読み取り/書き込みの競合が発生する可能性が高くなることがわかります (たとえば、RC レベルでは、トランザクション A がデータ行 1 を更新し、トランザクション B はトランザクション A がコミットする前にデータ行 1 を読み取り、トランザクション A がコミットしてロックを解除するまで待機する必要があります)。 ロックなしで読み取り/書き込み競合の問題を解決するために、MySQL は MVCC メカニズムを導入しました。詳細については、以前の分析記事「データベースの楽観的ロック、悲観的ロック、および MVCC を 1 つの記事で理解する」を参照してください。 InnoDB トランザクション分離レベルの実装原則先に進む前に、いくつかの概念を理解する必要があります。 1. ロック読み取りと一貫性のある非ロック読み取り 読み取りのロック: SELECT ... LOCK IN SHARE MODE や SELECT ... FOR UPDATE などのトランザクションで読み取りをアクティブにロックします。行共有ロックと行排他ロックがそれぞれ追加されます。ロックの分類については、以前の分析記事「知っておくべき MySQL ロックの分類」で確認できます。
一貫性のある非ロック読み取り: InnoDB は MVCC を使用して、トランザクションのクエリに対して特定の時点でのデータベース スナップショットを提供します。クエリでは、その時点より前にコミットされたトランザクションによって行われた変更は参照されますが、それ以降のトランザクションまたはコミットされていないトランザクションによって行われた変更は参照されません (このトランザクションを除く)。つまり、トランザクションが開始された後、トランザクションによって表示されるデータは、トランザクションが開始された瞬間のデータのみであり、他のトランザクションのその後の変更はこのトランザクションでは表示されません。 一貫性のある読み取りは、InnoDB が RC および RR 分離レベルで SELECT ステートメントを処理するためのデフォルト モードです。一貫性のある非ロック読み取りでは、アクセスするテーブルにロックが設定されないため、一貫性のある非ロック読み取りがテーブルで実行されている間に、他のトランザクションが同時にテーブルを読み取ったり変更したりできます。
2. 現在の読み取りとスナップショットの読み取り 現在の読書 読み取られるのは最新バージョンです。UPDATE、DELETE、INSERT、SELECT ... LOCK IN SHARE MODE、SELECT ... FOR UPDATE などの操作はすべて現在の読み取りです。なぜ現在の読み取りと呼ばれるのでしょうか?つまり、レコードの最新バージョンを読み取ります。読み取り時には、他の同時トランザクションが現在のレコードを変更できないようにする必要があり、読み取られたレコードはロックされます。 スナップショット読み取り 読み取られるのはスナップショット バージョン、つまり履歴バージョンです。たとえば、ロック解除された SELECT 操作はスナップショット読み取り、つまりロック解除された非ブロッキング読み取りです。スナップショット読み取りの前提は、分離レベルが非コミット読み取りまたはシリアル読み取りレベルではないことです。これは、非コミット読み取りでは常に最新のデータ行が読み取られ、現在のトランザクション バージョンに準拠するデータ行が読み取られないためです。シリアル読み取りではテーブルがロックされます。 3. 暗黙のロックと明示的なロック 暗黙のロック InnoDB は、トランザクション実行中に 2 フェーズ ロック プロトコルを使用します (明示的なロックを積極的に実行しません)。
明示的なロック
select ... lock in share mode //共有ロック select ... for update //排他ロック
ロックテーブル テーブルのロックを解除 上記の概念を理解した後、InnoDBトランザクションがどのように実装されているかを見てみましょう(次の読み取りは、アクティブにロックされていない選択を参照します)。
ご覧のとおり、InnoDB は MVCC を通じて読み取り書き込み競合の問題を非常にうまく解決し、標準レベルで発生するファントム読み取りと非反復読み取りの問題を 1 レベル先に解決して、データベースの同時実行能力を大幅に向上させます。 よくある誤解ファントムリードには削除が含まれますか?反復不可能な読み取り: 行が前後に複数回読み取られ、データの内容に一貫性がなく、他のトランザクションの更新および削除操作です。この問題を解決するには、行共有ロックを使用して、トランザクションの終了までロックします (つまり、RR レベル)。もちろん、MySQL は MVCC を使用して、RC レベルでこの問題を解決します。 ファントム リード: ファントム リードは、同じクエリが異なる時間に異なる行セットを生成する場合に発生します。これは、他のトランザクションの挿入操作によって発生します。この問題を解決するには、トランザクションが終了するまでテーブル全体をロックします (つまり、S レベルです。もちろん、MySQL は RR レベルでギャップ ロックを使用してこの問題を解決します)。 インターネット上の多くの記事では、ファントム リードとコミット リードについて言及しています。ファントム リードには削除も含まれると言う人もいれば、削除はコミット リードの問題として考えるべきだと言う人もいます。では、真実は何でしょうか。実際にMySQLの公式ドキュメントを見てみましょう(以下の通り)
ファントム リードは結果セットの前後の変更を対象としていることがわかります。そのため、削除の状況はファントム リードに分類されると思われます。ただし、実際に上記の標準 SQL の実装原理を RR レベルで分析すると、標準 SQL の RR レベルでは、見つかったデータ行に行共有ロックが追加されるため、この時点で他のトランザクションはこれらのデータ行を削除できないことがわかります。したがって、RR では、削除によるファントム リードは発生しません。つまり、ファントム リードには削除は含まれません。 MVCC はファントム リーディング問題を解決できますか?インターネット上の多くの記事では、MVCC または MVCC+ギャップ ロックがファントム リード問題を解決すると書かれています。実際には、MVCC ではファントム リード問題を解決できません。例えば: 始める; #users テーブルが空であると仮定すると、以下で見つかったデータは空です。 select * from users; #ロックなし #この時点で、別のトランザクションがコミットされ、id=1 のデータが挿入されます。 select * from users; #スナップショットを読み取ると、見つかったデータは空です。 update users set name='mysql' where id=1; #update は現在の読み取りであるため、更新は成功し、更新されたスナップショットが生成されます。 select * from users; #スナップショットを読み取り、id 1 のレコードを見つけます。MVCC は現在のトランザクションによって生成されたスナップショットを見つけることができるためです。 commit; 前後でチェックしたデータ行に不整合があり、ファントムリードが発生していることがわかります。したがって、MVCC だけではファントム リードの問題を解決することはできません。ファントム リードの問題を解決するには、ギャップ ロックが必要です。次のように: 始める; #users テーブルが空で、以下が見つかったデータが空であると仮定します。select * from users lock in share mode; #共有ロックを追加します。#この時点で、別のトランザクション B がコミットして、id=1 のデータを挿入します。ギャップ ロックのため、待機する必要があります。select * from users; #スナップショットを読み取ります。見つかったデータは空です。update users set name='mysql' where id=1; #update は現在の読み取りであり、データが存在しないため更新は実行されません。select * from users; #スナップショットを読み取ります。見つかったデータは空です。commit; #トランザクションBが正常に送信され、データが挿入されます RR レベルでファントム リード問題を解決するには、明示的にロックする必要があります。そうしないと、クエリ中にロックされません。 上記は、MySQL におけるトランザクション分離レベルの実装原理の詳細な説明です。MySQL トランザクション分離レベルの詳細については、123WORDPRESS.COM の他の関連記事に注目してください。 以下もご興味があるかもしれません:
|
<<: Dockerイメージのインポートとエクスポートの実装
>>: XHTMLコードの一般的なアプリケーション問題をまとめる
目次バイト機能使用環境プロジェクトを構築する構成vite.config.ts tsconfig.js...
PS: 最近、nginx を詳細に紹介している <<High-Performance ...
Navicat がエクスポートしたデータはインポートできません。最後に、MySQLコマンドのインポー...
404 を避けるべきだとどうして言えるのでしょうか? その理由は、ほとんどの 404 ページが粗雑す...
導入この記事では、Ubuntu 18.04 デスクトップ システムでディスクを目的のディレクトリにマ...
1. Javascript は前のページ history.go(-1) に戻り、2 つのページを返し...
現在の時刻を取得します: current_timestamp を選択します。出力: 2016-06-...
Jenkinsのユーザーロール権限の設定には、ロール戦略プラグインのインストールが必要です。 1.ロ...
ウェブページに表示されるプレーヤーは、WMP/RealPlayer/Flash Player に過ぎ...
今日、ある人がウェブサイト開発プロジェクトについて話をしてくれました。具体的な要件について話すと、「...
主に使用される知識ポイント: •css3 3D変換 •ネイティブjsマウスドラッグイベント•表示:グ...
MySQLをアンインストールする1. コントロールパネルで、MySQLのすべてのコンポーネントをア...
先ほど、適応幅と高さが1:1の正方形を作成する方法について説明しました。 https://www.j...
エラーシナリオcmd の mysql コマンドを使用して、学生情報テーブルにデータを追加します。デー...
インタビュアー: Vue のソースコードを読んだことはありますか?応募者:あります。インタビュアー:...