MySql 学習ノートにおけるトランザクション分離レベルの詳細な説明

MySql 学習ノートにおけるトランザクション分離レベルの詳細な説明

背景

トランザクションについて話すとき、誰もがそれに精通している必要があります。MySQL データベースを使用して開発する場合、通常はトランザクションを使用します。典型的な例は送金です。たとえば、Xiao Ming に 50 元を送金したいのですが、その時点で銀行カードには 50 元しかありません。

振替処理のコードプログラムには、口座残高の確認、残高の増減、残高の更新など、一連の操作があります。これらの操作は一緒に処理する必要があります。そうしないと、プログラムがチェックを終えた後、口座に50元がまだ残っていて、そのお金を別の友人に振り込むと、銀行も処理し、プロセス全体のデータの一貫性が保証されなくなると、混乱しませんか?ここで「トランザクション」が関係してきます。

取引紹介

簡単に言えば、トランザクションは、一連のデータベース操作がすべて正常に実行されるか、すべて失敗するかのいずれかを保証するものです。 MySQL では、トランザクション サポートはエンジン レベル (InnoDB) で実装されています。 MySQL は複数のエンジンをサポートするシステムですが、すべてのエンジンがトランザクションをサポートしているわけではありません。たとえば、MySQL のネイティブ MyISAM エンジンはトランザクションをサポートしていません。これが、MyISAM が InnoDB に置き換えられた重要な理由の 1 つです。

この記事では、InnoDB を例に、MySQL トランザクション サポートのいくつかの実装について説明し、原則に基づいて対応する実用的な提案を示します。これらの説明を通じて、MySQL トランザクションの原則に対する理解を深めることができます。

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

トランザクションといえば、ACID (原子性、一貫性、独立性、永続性) を思い浮かべるでしょう。I、つまり「独立性」についてお話ししましょう。

データベース上で複数のトランザクションが同時に実行されると、ダーティ リード、非反復リード、ファントム リードが発生する可能性があります。これらの問題を解決するために、「分離レベル」という概念が導入されました。

分離レベルについて話す前に、まず、分離が厳しくなるほど効率が低くなることを知っておく必要があります。したがって、多くの場合、両者のバランスを見つける必要があります。 SQL 標準のトランザクション分離レベルには、コミットされていない読み取り、コミットされた読み取り、繰り返し読み取り、およびシリアル化可能が含まれます。一つずつ説明します。

  • コミットされていない読み取りとは、トランザクションがコミットされていない場合、そのトランザクションによる変更が他のトランザクションで確認できることを意味します。
  • 読み取りコミットとは、トランザクションがコミットされた後、そのトランザクションによる変更が他のトランザクションにも表示されることを意味します。
  • 繰り返し可能な読み取りとは、トランザクションの実行中に表示されるデータが、トランザクションの開始時に表示されたデータと常に一貫していることを意味します。もちろん、繰り返し読み取り分離レベルでは、コミットされていない変更は他のトランザクションには表示されません。
  • シリアル化とは、その名前が示すように、同じレコード行に対して、「書き込み」によって「書き込みロック」が追加され、「読み取り」によって「読み取りロック」が追加されることを意味します。読み取り/書き込みロックの競合が発生した場合、後からアクセスされるトランザクションは、前のトランザクションが完了するまで待機してから実行を続行する必要があります。

その中で、「Read Committed」と「Repeatable Read」は理解しにくいので、例を使ってこれらの分離レベルを説明しようと思います。データテーブル t_student に列が 1 つだけあり、1 行の値が 21 であるとします。以下は、2 つのトランザクションを時系列順に実行した場合の動作です。

mysql> テーブル t_student(age int) を作成します。engine=InnoDB;
mysql> t_student(age) に値(21) を挿入します。

異なる分離レベルでは、トランザクション A の異なる戻り結果は何ですか? つまり、図の V1、V2、V3 の戻り値はそれぞれ何ですか?分離レベルが「コミットされていない読み取り」の場合、V1 の値は 22 になります。この時点ではトランザクション B はまだコミットされていませんが、その結果は A に表示されます。したがって、V2 と V3 も 22 です。

分離レベルが「読み取りコミット」の場合、V1 は 21、V2 は 22 になります。トランザクション B の更新は、コミットされた後にのみ A に表示されます。したがって、V3 の値も 22 になります。

分離レベルが「繰り返し読み取り」の場合、V1 と V2 は 21、V3 は 22 になります。 V2 がまだ 21 である理由は、実行中にトランザクションによって確認されるデータは一貫している必要があるという原則に従っているためです。

分離レベルが「シリアル化」の場合、トランザクション B が「21 を 22 に変更」を実行すると、ロックされます。トランザクション B は、トランザクション A がコミットされた後にのみ実行を続行できます。したがって、Aの観点から見ると、V1とV2の値は21、V3の値は22です。

実装では、データベースにビューが作成され、ビューの論理結果がアクセスの基準として使用されます。 「繰り返し可能読み取り」分離レベルでは、このビューはトランザクションの開始時に作成され、トランザクション全体で使用されます。

「Read Committed」分離レベルでは、このビューは各 SQL ステートメントの実行の開始時に作成されます。ここで注目すべきは、「コミットされていない読み取り」分離レベルでは、ビューの概念を使用せずにレコードの最新の値を直接返すのに対し、「シリアル化可能」分離レベルでは、並列アクセスを回避するためにロックを直接使用するということです。

分離レベルが異なるとデータベースの動作が異なることがわかります。 Oracle データベースのデフォルトの分離レベルは、実際には「読み取りコミット」です。したがって、Oracle から MySQL に移行された一部のアプリケーションでは、データベース分離レベルの一貫性を確保するために、MySQL の分離レベルを「読み取りコミット」に設定することを忘れないでください。

構成方法は、起動パラメータ transaction-isolation の値を READ-COMMITTED に設定することです。現在の値を表示するには、showvariables を使用できます。

mysql> 'transaction_isolation' のような変数を表示します。

一般的に、存在することは合理的です。各分離レベルには独自の使用シナリオがあり、独自のビジネス状況に基づいて決定する必要があります。 「繰り返し読み取り」シナリオはいつ必要になるのかと疑問に思う人もいるかもしれません。データ校正ロジックのケーススタディを見てみましょう。

銀行口座テーブルを管理しているとします。1 つのテーブルには毎月末の残高が保存され、もう 1 つのテーブルには請求書の詳細が保存されます。このとき、データの校正、つまり先月の残高と現在の残高の差が今月の請求明細と一致しているかどうかを判断する必要があります。校正プロセス中に、ユーザーが新しいトランザクションを実行しても、校正結果に影響が及ばないことを期待する必要があります。このとき、「繰り返し読み取り」分離レベルを使用すると便利です。トランザクションが開始されたときのビューは静的であるとみなされ、他のトランザクションからの更新の影響を受けません。

トランザクション分離の実装

トランザクション分離レベルを理解したので、トランザクション分離がどのように実装されるかを見てみましょう。ここでは「繰り返し読み取り」について詳しく説明します。実際、MySQL では、各レコードが更新されると、ロールバック操作が記録されます。レコードの最新の値を使用して、ロールバック操作を通じて以前の状態の値を取得できます。

値が 1 から 2、3、4 に順番に変更され、元に戻すログに次のようなレコードが含まれると仮定します。

現在の値は 4 ですが、このレコードを照会すると、異なる時間に開始されたトランザクションには異なる読み取りビューが設定されます。図に示すように、ビュー A、B、C では、このレコードの値はそれぞれ 1、2、4 です。同じレコードがシステム内で複数のバージョンを持つことができ、これがデータベースのマルチバージョン同時実行制御 (MVCC) です。読み取りビュー A の場合、1 を取得するには、図内のすべてのロールバック操作を順番に実行して現在の値を取得する必要があります。

同時に、4 を 5 に変更する別のトランザクションがある場合でも、このトランザクションは read-viewA、B、および C に対応するトランザクションと競合しないことがわかります。
ロールバック ログは永久に保存することはできないので、いつ削除すればよいのかと疑問に思う人もいるかもしれません。もちろん、必要なくなったら削除されます。つまり、システムは、これらのロールバック ログを使用する必要のあるトランザクションがない場合、ロールバック ログを削除すると判断することになります。

それで、問題は、いつそれが不要になるのかということです。それは、このロールバック ログより前の読み取りビューがシステム内に存在しない場合です。

上記の説明に基づいて、長いトランザクションの使用をできるだけ避けることが推奨される理由について説明しましょう。

まず、長いトランザクションは、システム内に非常に古いトランザクション ビューが存在することを意味します。これらのトランザクションはいつでもデータベース内の任意のデータにアクセスする可能性があるため、トランザクションがコミットされる前に、データベース内で使用される可能性のあるすべてのロールバック レコードを保持する必要があり、その結果、大量のストレージ領域が占有されることになります。

MySQL 5.5 以前のバージョンでは、ロールバック ログはデータ ディクショナリとともに ibdata ファイルに配置されます。長いトランザクションが最終的にコミットされ、ロールバック セグメントがクリーンアップされても、ファイルは小さくなりません。たった 10 GB のデータと 100 GB のロールバック セグメントしかないライブラリを見たことがあります。結局、ロールバック セグメントをクリーンアップするためにライブラリ全体を再構築する必要がありました。
ロールバック セグメントへの影響に加えて、長いトランザクションはロック リソースも占有し、データベース全体がダウンする可能性もあります。

トランザクション開始モード

前述の長期取引にはこうした潜在的なリスクが伴うため、当然ながら可能な限り回避することが推奨されます。実際、ビジネス開発者は長いトランザクションを意図的に使用するのではなく、誤用が原因で使用することがよくあります。 MySQL トランザクションを開始する方法はいくつかあります。

  1. トランザクション ステートメントを明示的に開始し、トランザクションを開始または開始します。対応するコミット ステートメントは commit であり、対応するロールバック ステートメントは rollback です。
  2. autocommit=0 を設定すると、このコマンドはこのスレッドの自動コミットをオフにします。つまり、select ステートメントのみを実行すると、トランザクションが開始されますが、自動的にコミットされません。このトランザクションは、コミットまたはロールバック ステートメントをアクティブに実行するか、切断するまで存続します。

一部のクライアント接続フレームワークでは、接続が成功した後、デフォルトで set autocommit=0 コマンドが実行されます。これにより、後続のすべてのクエリがトランザクション内に含まれるようになり、接続が長い場合は、予想外に長いトランザクションが発生します。

したがって、常に set autocommit=1 を使用し、明示的なステートメントを通じてトランザクションを開始することをお勧めします。しかし、開発者の中には、「もう 1 つのインタラクション」の問題に悩まされる人もいるかもしれません。トランザクションを頻繁に使用する必要があるビジネスの場合、2 番目の方法では、各トランザクションの開始時に「begin」をアクティブに実行する必要がないため、ステートメントの対話回数が削減されます。このような懸念がある場合は、コミット作業とチェーン構文を使用することをお勧めします。

autocommit が 1 の場合、begin で明示的に開始されたトランザクションは、commit が実行されるとコミットされます。 commit work and chain が実行されると、トランザクションがコミットされ、次のトランザクションが自動的に開始されるため、begin ステートメントを再度実行するオーバーヘッドも節約されます。メリットは、プログラム開発の観点から、各ステートメントがトランザクション内にあるかどうかを明確に把握できることです。 information_schema ライブラリの innodb_trx テーブルで長いトランザクションをクエリできます。

要約する

主に、MySQL のトランザクション分離レベルの現象と実装について説明し、実装原則に基づいて長いトランザクションのリスクを分析し、長いトランザクションを適切に回避する方法について説明します。これらのトランザクションの原則を理解することで、MySQL のトランザクション機能をより有効に活用できるようになります。

MySQL の勉強ノートとトランザクション分離レベルに関する記事はこれで終わりです。MySQL のトランザクション分離レベルについての詳細は、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • MySQL 学習ノート ヘルプ ドキュメント
  • MySQL 学習ノート: データ エンジン
  • MySQLの基礎知識学習ノート
  • MySQL 学習ノート: データの追加、削除、変更方法
  • MySQL 学習ノート: テーブルの作成、削除、変更方法
  • MySQL学習ノートの要約
  • 1,000行のMySQL学習ノートの要約
  • MySQL 学習ノート 5: テーブルの変更 (alter table)
  • MySQL 学習ノート 4: 整合性制約制限フィールド
  • MySQL 学習ノート 1: インストールとログイン (複数の方法)
  • 完全なMySQL学習ノート

<<:  HTMLのmarquee属性でテキストを踊らせる

>>:  ウェブページ制作と饅頭の関係(体験の共有)

推薦する

Linux Centos7 に mysql8 をインストールするチュートリアル

1. RPMバージョンのインストールデータベースの他のバージョンがあるかどうかを確認し、ある場合は完...

Windows および Linux での Redis のインストールとデーモン設定

# Windows および Linux 上の Redis のインストール デーモン構成Redis の...

純粋な CSS で中空効果を実現するためのサンプルコード

私は最近、空洞化効果について研究しました。背景クリップ: テキスト背景はテキストの前景色にクリップさ...

MySQL は対応するクライアント プロセスにどのように接続しますか?

質問特定の MySQL 接続について、それがどのクライアント プロセスからのものであるかをどのように...

Ubuntu 18.04の下のディレクトリにディスクをマウントします

導入この記事では、Ubuntu 18.04 デスクトップ システムでディスクを目的のディレクトリにマ...

CentOS VPS に SSH 経由で MySQL をインストールする方法

yum install mysql-serverと入力します。続行するにはYを押してくださいインスト...

ページネーションの例とベストプラクティス

<br />構造と階層により複雑さが軽減され、読みやすさが向上します。記事やサイトが整理...

Sublime TextがUbuntuで中国語を入力できない問題の最も簡単な解決策

崇高なSublime Text はコード エディター (Sublime Text2 は有料ソフトウェ...

PostgreSQL正規表現の一般的な機能の概要

PostgreSQL正規表現の一般的な機能の概要正規表現は、複雑なデータ処理を必要とするプログラムに...

Nginx設定の原理と実装プロセスの詳細な説明https

Linuxユーティリティcertbotを使用してhttps証明書を生成するこのツールは Let&#...

CSS を使用して 3 つのステップでショッピング モールのカード クーポンを作成する

今日は618日、主要なショッピングモールはすべてプロモーション活動を行っています。今日は、次のように...

MySQL に配列を保存するサンプルコードと方法

多くの場合、ストアド プロシージャを作成するときに配列がよく使用されますが、MySQL ではストアド...

IPとポートが接続可能かどうかを検出する方法

Windows コマンドテルネット形式: telnet IP ポート場合: テルネット 191.1....

RedisとMySQLの違いを簡単に説明してください

MySQL はディスクに保存される永続的なストレージであり、取得には一定の IO が伴うことはご存じ...

CentOS 7 での Docker プロキシの設定 (Linux での Systemd サービスの環境変数設定)

Docker デーモンは、 HTTP_PROXY 、 HTTPS_PROXY 、およびNO_PRO...