MySQLにおけるACIDトランザクションの実装原理の詳細な説明

MySQLにおけるACIDトランザクションの実装原理の詳細な説明

導入

いつものように、シーンから始めましょう〜

インタビュアー:「トランザクションの4つの特性をご存知ですか?」
あなた: 「はい、ACID、原子性、一貫性、独立性、耐久性です!」
インタビュアー: 「MySQL データベースをお使いですね。InnoDB でこれらの 4 つの機能がどのように実装されているか、簡単に説明していただけますか?」
あなた:「隔離の仕方しか知らないバラバラ~~」
面接官「戻って通知を待ったほうがいいですよ~」

さて、本題に戻りましょう。トランザクションの 4 つの主要な特性である、原子性、一貫性、独立性、永続性については、多くの人が理解しています。しかし、もう少し具体的に考えてみましょう。これらの 4 つの機能はデータベースにどのように実装されているのでしょうか?すると、この質問に答えられる人はほとんどいないでしょう。したがって、この記事では、MySQL の 4 つの主要機能の実装原則に焦点を当てます。

文章

ACID の 4 つの主要な特性を説明するために、口座 A から口座 B に 50 元を送金する例を見てみましょう。

原子性

定義上、アトミック性とは、トランザクションがすべての操作が実行されるか、まったく操作が実行されない、分割できない作業単位であることを意味します。つまり、転送は成功するか失敗するかのどちらかであり、中間の状態はありません。

原子性が保証できない場合はどうなりますか?

データの不整合が発生し、アカウント A は 50 元減額され、アカウント B は 50 元増加し、操作は失敗します。システムは理由もなく50元を失います〜

分離

定義上、分離とは、複数のトランザクションが同時に実行される場合、トランザクション内の操作が他のトランザクションから分離され、同時に実行されるトランザクションが互いに干渉できないことを意味します。

分離が保証できない場合はどうなりますか?

さて、口座 A に 200 元、口座 B に 0 元があるとします。口座Aは口座Bに合計50元を2回送金し、それぞれ2回の取引で実行しました。隔離が保証できない場合、次のような状況が発生する可能性があります。


図に示すように、分離が保証されていない場合、A は 2 回お金を差し引きますが、B は 1 回だけお金を追加し、50 元が突然消えてしまい、データの不整合が依然として発生します。

追記: 注意深い読者は、MySQL が分離の問題を解決するためにロックに依存していることに気付いたかもしれません。まあ、それは後で説明します。

持続性

定義上、耐久性とは、トランザクションがコミットされると、データベースへの変更が永続的になることを意味します。その後の他の操作や障害は、これに何ら影響を与えないはずです。

永続性が保証できない場合はどうなりますか?

MySQL では、CPU とディスクの速度が一致しない問題を解決するために、ディスク上のデータをメモリにロードし、メモリ上で操作してからディスクに書き戻します。さて、この時点でサーバーがクラッシュすると、メモリ内で変更されたデータはすべて失われ、永続性が保証されなくなります。

転送が成功したことをシステムが通知すると想像してください。しかし、金額がまったく変わっていないことがわかります。このとき、データは不正な状態にあります。この状態をデータの不整合とみなします。

一貫性

定義上、一貫性とは、トランザクションが実行される前と実行後にデータが正当な状態にあることを意味します。この状態は、構文的ではなく意味的です。
では、法的なデータのステータスはどうなっているのでしょうか?

わかりました。この状態は、事前に決められた制約を満たしている場合、合法的な状態と呼ばれます。より一般的な言葉で言えば、この状態はあなたによって定義されます。この状態が満たされると、データは一貫しています。この状態が満たされない場合、データは不整合です。

一貫性が保証できない場合はどうなりますか?

例1:口座Aに200元があり、300元が送金されます。このとき、口座Aの残高は-100元です。この時点では、当然ながらデータに矛盾があることがわかります。なぜでしょうか?状態を定義したため、残高列は 0 より大きくなければなりません。

例 2: 口座 A に 200 元があり、50 元が口座 B に振り込まれます。口座 A のお金は差し引かれますが、さまざまな予期しないイベントにより口座 B の残高は増加しません。現時点ではデータが矛盾していることもご存知ですが、その理由は何ですか? A + B のバランスが変化しないことを要求する状態を定義したためです。

実用的な答え

質問 1: Mysql はどのようにして一貫性を確保するのでしょうか?

さて、この質問は 2 つのレベルに分けることができます。

データベース レベルでは、データベースは原子性、分離性、永続性を通じて一貫性を保証します。つまり、ACID の 4 つの主要特性のうち、C (一貫性) は目的であり、A (原子性)、I (独立性)、D (永続性) は、一貫性を確保するためにデータベースによって提供される手段です。一貫性を実現するには、データベースで AID の 3 つの主要な特性を実装する必要があります。たとえば、原子性は保証できず、当然一貫性も保証できません。

ただし、トランザクション内の制約に違反するコードを意図的に記述すると、一貫性は保証されません。たとえば、転送の例では、コードが意図的にアカウント B に資金を追加しない場合、一貫性は保証されません。そのため、アプリケーション層も考慮する必要があります。

アプリケーション レベルでは、コードを使用してデータベース データが有効かどうかを判断し、データをロールバックするかコミットするかを決定します。

質問 2: Mysql はどのようにして原子性を保証するのでしょうか?

OK、Innodb の undo ログを使用することです。

UNDO ログはロールバック ログと呼ばれ、アトミック性を実現するための鍵となります。トランザクションがロールバックされると、正常に実行されたすべての SQL ステートメントが取り消されます。ロールバックする対応するログ情報を記録する必要があります。

例えば

  • (1)データを削除する場合は、そのデータの情報を記録する必要があります。ロールバックする場合は、古いデータを挿入します。
  • (2)データを更新する場合は、古い値を記録しておく必要があります。ロールバックする場合は、古い値に基づいて更新操作を実行します。
  • (3)データを挿入する場合は、レコードの主キーが必要です。ロールバックする場合は、主キーに基づいて削除操作が実行されます。

UNDO ログには、ロールバックに必要な情報が記録されます。トランザクションが失敗した場合、またはロールバックが呼び出されてトランザクションがロールバックされた場合、UNDO ログの情報を使用して、データを変更前の状態にロールバックできます。

ps: 具体的な元に戻すログはどのようになっているのでしょうか? これは記事に書くことができます。さらに、書いても読む人はあまりいないので、とりあえずシンプルにしておきましょう。

質問 3: Mysql はどのようにして永続性を確保するのでしょうか?

OK、Innodb の redo ログを使用します。

前述したように、MySQL はまずディスク上のデータをメモリにロードし、メモリ内のデータを変更してから、それをディスクにフラッシュします。このときにコンピュータが突然クラッシュすると、メモリ内のデータが失われます。

この問題を解決するにはどうすればいいでしょうか?

簡単です。トランザクションをコミットする前にデータをディスクに書き込むだけです。

こうすると何が問題なのですか?

  • ページ内の 1 バイトだけを変更するには、ページ全体をディスクにフラッシュする必要があり、これはリソースの無駄になります。結局のところ、ページのサイズは 16kb です。ほんの少し変更しただけでも、16kb のコンテンツをディスクにフラッシュする必要がありますが、これは合理的とは言えません。
  • 結局のところ、トランザクション内の SQL には複数のデータ ページの変更が含まれる可能性があり、これらのデータ ページは隣接していない可能性があり、これはランダム IO を意味します。当然、ランダム IO 操作の速度は遅くなります。

そこで、上記の問題を解決するためにREDOログを使用することが決定されました。データが変更されると、メモリ内で実行されるだけでなく、REDO ログにも記録されます。トランザクションがコミットされると、REDO ログがディスクにフラッシュされます (REDO ログの一部はメモリ内にあり、一部はディスク上にあります)。データベースがクラッシュして再起動すると、REDO ログの内容がデータベースに復元され、UNDO ログと binlog の内容に基づいてデータをロールバックするかコミットするかが決定されます。

REDO ログを使用する利点は何ですか?

実際、REDOログをディスクにフラッシュする方がデータページをディスクにフラッシュするよりも効率的であるという利点があります。具体的なパフォーマンスは次のとおりです。

  • REDO ログは、結局のところ、どのページが変更されたかを記録するだけなので、サイズが小さく、フラッシュも高速です。
  • REDO ログは常に末尾に追加され、シーケンシャル IO に属します。効率はランダム IO よりも明らかに高速です。

追伸: 内容が多すぎるため、REDO ログがどのようになっているかについては詳しく説明したくありません。

質問 4: Mysql はどのようにして分離を確保するのでしょうか?

OK、ロックと MVCC メカニズムが使用されます。振替の例を例に挙げて説明しましょう。次のような口座表があります。

テーブル名 t_balance

idユーザーIDバランス
1200
2 B 0

このうち、id は主キー、user_id はアカウント名、balance は残高です。次の図に示すように、2回送金する例を見てみましょう。

MVCC (Multi Version Concurrency Control) の場合、レコード データ行には複数のバージョンのスナップショット データが含まれており、これらのスナップショット データは UNDO ログに保持されます。

トランザクションが DELETE または UPDATE 中の行を読み取る場合、読み取り操作は行のロックが解除されるのを待たずに、行のスナップショット バージョンを読み取ります。

MVCC の仕組みは、Repeatable Read と Read Commited MVCC で表現が異なるため、詳細には触れません。

ただし、注意すべき点の 1 つは、トランザクション分離レベルが Read Committed の場合、トランザクションは別のトランザクションによってコミットされたデータを読み取ることができ、分離要件を満たさないことです。ただし、トランザクション分離レベルが Repeatable Read の場合、分離は満たされます。

要約する

この記事では、MySQL トランザクションの 4 つの主要な ACID 特性の実装原則について説明します。ご参考になれば幸いです。

さて、今回の記事は以上です。この記事の内容が皆さんの勉強や仕事に少しでも参考になれば幸いです。123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • MySQL は ACID トランザクションをどのように実装しますか?
  • MySQLの驚くべき暗黙の変換
  • MySQL の null 制約のケースの説明
  • MySQLデータベース移行におけるデータ文字化けの問題を解決する
  • MySQL 接続例外とエラー 10061 の解決方法
  • MySQL トランザクション制御フローと ACID 特性

<<:  CentOS 8 に Postfix メール サーバーをインストールして設定する方法

>>:  WeChatアプレットは固定ヘッダーとリストテーブルコンポーネントを実装します

推薦する

HTML 左、中央、右の適応レイアウト (calc css 式を使用)

最新の HTML 標準には、レイアウトを計算するために使用できる calc CSS 式があります。し...

Nginx Rewrite の使用シナリオとコード例の詳細な説明

Nginx Rewriteの使用シナリオ1. URL アドレスジャンプ。たとえば、ユーザーが pm....

Docker 構成コンテナの場所とヒントのまとめ

Docker の使用に関するヒント1. 停止したDockerコンテナをすべてクリーンアップする停止し...

Linux インデックスノード inode の詳細な説明

1. inodeの紹介inode を理解するには、まずファイル ストレージから始める必要があります。...

CSS3はグラフィックの落下アニメーション効果を実現します

まずは効果を確認実装コード <div class="box box1"&g...

mysql はインデックスを無効にしますか?

mysql の IN はインデックスを無効にしますか?しませんよ! 結果をご覧ください: mysq...

CentOS 6.5 i386 インストール MySQL 5.7.18 詳細チュートリアル

ほとんどの人はMySQLをコンパイルしてシステムディレクトリに置きますが、私のやり方はコンパイルした...

JS の 3 つの主要な問題、非同期性とシングルスレッドについて簡単に説明します。

目次シングルスレッド非同期シングルスレッドしかし、開発中にネットワーク リクエストやスケジュールされ...

MySQL テーブル自動増分 ID オーバーフロー障害レビュー ソリューション

問題: MySQLテーブル内の自動増分IDのオーバーフローによりビジネスブロックが発生した背景: t...

Vue でスロットを使用する方法についての簡単な説明

定義と使用方法:コンポーネントのテンプレートでスロットタグの定義を使用します。デフォルトの表示値は、...

MySQL でのトリガーとカーソルの紹介と使用

トリガーの紹介トリガーは、テーブルに関連付けられた特別なストアド プロシージャであり、テーブル内のデ...

Ubuntu 18.04にmysql5.7をインストールする

Ubuntu 18.04では参考までにmysql 5.7をインストールします。具体的な内容は以下のと...

MySQLのREDOログとUNDOログの詳細な説明

MySQL ログ システムで最も重要なログは、REDO ログとアーカイブ ログです。後者は MySQ...

CSS3 引用のソースと出典をマークする方法

疫病のせいで家にこもりきりで、頭がおかしくなりそうなので、パソコンを起動して頭を働かせてみました。今...