面接では、面接官は MySQL の ACID について質問するだけで、すぐに 8 部構成のエッセイを暗唱できます (まだ答えられない人もいるかもしれません)。さらに腹立たしいのは、一部の面接官がルーチンに従わず、「MySQL は ACID をどのように実装するのですか?」と質問し続けることです。
私は混乱しています。正直に言うと、この質問は 95% の人を説得できます。
今日の記事では、MySQL InnoDB
エンジンにおける ACID の実装原理について主に説明し、トランザクションとは何か、分離レベルの意味などの基礎知識についてはあまり詳しく説明しません。 。
リレーショナル データベースとして、MySQL は最も一般的な InnoDB エンジンを使用して ACID を保証します。
まずは分離について説明しましょう。最初は 4 つの分離レベルです。
説明 | |
---|---|
いつトランザクションが送信されていない場合、その変更は他のトランザクションから確認できます | |
トランザクションが送信された後、その変更は他のトランザクションからのみ確認できます。他のトランザクションで表示されます。他のトランザクションで表示されます | |
反復読み取り | トランザクションでは、他のトランザクションがデータを操作しているかどうか、トランザクションがコミットされているかどうかに関係なく、同じデータを読み取った結果は常に同じです。 InnoDB のデフォルト レベル 。 |
シリアル化 | トランザクションはシリアルに実行されます。各読み取りにはテーブルレベルの共有ロックが必要です。読み取りと書き込みは相互にブロックされます。分離レベルは最高であり、犠牲になります。システムの同時実行性。 |
さまざまな分離レベルは、さまざまな問題を解決するために設計されています。つまり、ダーティ リード、ファントム リード、およびノンリピータブル リードです。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
表示される可能性がある | 表示される可能性がある | 表示される可能性がある | |
許可されません | 発生する可能性があります | 発生する可能性があります | |
許可されません | 許可されません | 表示できます | |
シリアル化 | 許可されません | 許可されません | 許可されません |
では、分離レベルが異なると、分離はどのように達成されるのでしょうか。また、異なるものが互いに干渉しないのはなぜでしょうか?答えは Locks と MVCC です。
まずロックについて話しましょう。MySQL にはいくつのロックがありますか?
粒度の観点から見ると、テーブル ロック、ページ ロック、および行ロックです。テーブル ロックには、意図的な共有ロック、意図的な排他ロック、自己増加ロックなどが含まれます。行ロックは、各エンジンによってエンジン レベルで実装されます。ただし、すべてのエンジンが行ロックをサポートしているわけではなく、たとえば、MyISAM エンジンは行ロックをサポートしていません。
InnoDB トランザクションでは、行ロックはインデックス上のインデックス エントリをロックすることによって実装されます。これは、InnoDB がインデックス条件を通じてデータを取得する場合にのみ行レベルのロックを使用し、それ以外の場合はテーブル ロックを使用することを意味します。行レベルのロックも、共有ロックと排他ロック、およびロックする前に取得する必要がある意図共有ロックと意図排他ロックの 2 つのタイプに分類されます。
選択...共有モードでロック
ロックします。 挿入、更新、削除、更新用
ロック。 行ロックは必要に応じて 追加されますが、必要がなくなってもすぐには解放されず、トランザクションが終了するまで解放されません。これは 2 フェーズ ロック プロトコルです。
単一行レコードのロックは、常にインデックス レコードをロックします。
ギャップ ロック、ファントム読み取りの理由を考えてください。実際、行ロックは行をロックすることしかできませんが、新しいレコードを挿入するときに更新する必要があるのは、「 「レコード間のギャップ」。 そこで、ギャップロックを追加してファントム読み取りを解決します。
ギャップロック記録ロック、開いたまま、閉じたままにします。
下部ロックの一般的な概要を参照できます。ロックを使用すると、トランザクションがデータを書き込んでいる間、他のトランザクションは書き込みロックを取得できず、データを書き込むことができなくなり、トランザクション間の分離がある程度確保されます。しかし、前述したように、 書き込みロックを追加した後、他のトランザクションもデータを読み取ることができるのはなぜですか? 読み取りロックが取得できないためではないでしょうか? ?
前述したように、ロックを使用すると、現在のトランザクションは書き込みロックなしではデータを変更できませんが、データの行を変更した場合でも読み取りは可能です。他のトランザクションによって送信された場合でも、同じ値を繰り返し読み取ることができます。これは MVCC、マルチバージョン同時実行制御、Multi-Version Concurrency Control です。
Innodb の行レコードの保存形式には、いくつかの追加フィールドがあります: DATA_TRX_ID および DATA_ROLL_PTR。
undo log
内のリンク リストの形式で編成されています。 ReadView は各 SQL の先頭で作成され、いくつかの重要な属性があります:#undo ログ: データが変更される前にログを記録します。これについては後で詳しく説明します。
DATA_TRX_ID 917e3f0558ad00bcb4c8735c75d3d7a5= low_limit_id:現在の読み取りビューが作成された後にデータが生成され、データが表示されません。
分離レベルによって異なります。
INSERT をターゲットにし、 非再現性は UPDATE をターゲットにします。 私たちはそれを予想していました 実際は 実際、MySQL反復読み取りの分離レベルはファントム読み取りの問題を完全に解決するわけではありませんが、解決します。データ読み取り時のファントム読み取りの問題。変更操作にはファントム リードの問題が依然として存在します。これは、MVCC がファントム リードの解決に完全ではないことを意味します。 原子性について話しましょう。前述したように、元に戻すログはログをロールバックします。分離 MVCC は、アトミック性と同様に、実際に達成するためにこれに依存します。アトミック性を実現する鍵は、トランザクションがロールバックされたときに、正常に実行されたすべての SQL ステートメントを元に戻せることです。 トランザクションがデータベースを変更すると、InnoDB は対応する Undo ログを生成します。トランザクションの実行が失敗するかロールバックが呼び出され、トランザクションがロールバックされると、Undo ログ内の情報を使用してロールバックできます。データを変更前の状態に戻します。 Undo ログは、SQL の実行に関連する情報を記録する論理ログです。ロールバックが発生すると、InnoDB は元に戻すログの内容に基づいて前の作業の逆を実行します。 更新操作を例に挙げます。トランザクションが更新を実行すると、生成された元に戻すログには、変更された行の主キーが含まれます (どの行が変更されたかを知るため) ) およびどの列が変更されたか、変更前後のこれらの列の値、およびその他の情報を使用すると、ロールバック時にデータを更新前の状態に復元するために使用できます。 Innnodb には多くのログがあり、永続性は REDO ログに依存しています。 永続性は間違いなく書き込みに関連しています。WAL テクノロジは MySQL でよく言及されています。WAL の正式名は Write-Ahead Logging です。その重要な点は次のとおりです。最初にログを書き込み、次にディスクに書き込みます。小さなお店で商売をするのと同じように、ピンクのボードと家計簿があり、来客時はまずピンクのボードに書き、暇なときは家計簿を書きます。 redo ログはこのピンク色のボードです。レコードを更新する必要がある場合、InnoDB エンジンはまずレコードを REDO ログに書き込みます (そしてメモリを更新します)。アップデートが完了しました。この操作記録は適切なタイミングでディスクに更新されますが、この更新は、店主が閉店後に行うときのように、システムが比較的アイドル状態のときに行われることがよくあります。 REDO ログには 2 つの特徴があります: REDO ログには 2 つの段階があります: コミット「2 フェーズ コミット」を使用しない場合、データベースの状態は、そのログを使用して復元されたライブラリの状態と一致しない可能性があります。では、最初にここに行き、もう 1 つを見てみましょう。 InnoDB はキャッシュも提供します。バッファ プールには、データベースにアクセスするためのバッファとしてディスク上のいくつかのデータ ページのマッピングが含まれています。 バッファ プールを使用すると、データの読み取りと書き込みの効率が大幅に向上しますが、新しい問題も発生します。MySQL がダウンすると、バッファ プール内の変更されたデータが更新されないということです。現時点では、ディスクにコピーするとデータが失われるため、トランザクションの耐久性は保証できません。 そこで、REDO ログを追加しました。 データが変更されると、バッファー プール内のデータの変更に加えて、その操作が REDO ログにも記録されます。 トランザクションが送信されると、fsync インターフェイスが呼び出されます。 REDO ログをフラッシュします。 MySQL がダウンした場合、再起動時に REDO ログ内のデータを読み取り、データベースを復元できます。 REDO ログは WAL (先行書き込みログ、先行書き込みログ) を使用します。すべての変更は最初にログに書き込まれ、次にバッファ プールに更新されるため、MySQL が原因でデータが失われることはありません。ダウンタイムが発生しないため、耐久性要件が満たされます。これを行うことには 2 つの利点があります: これについて言えば、書き込み操作やデータの回復にも使用される bin ログがあるのではないかと疑問に思われるかもしれません。違い? ステートメント なぜ最初に REDO ログを書き込むのでしょうか? 一貫性は、トランザクションによって追求される最終的な目標です。前の質問で述べたアトミック性と耐久性です。セキュリティと分離は、実際にはデータベース状態の一貫性を確保するために行われます。もちろん、上記はすべてデータベース レベルでの保証であり、整合性の実装にはアプリケーション レベルでの保証も必要です。 つまり、あなたのビジネスです。たとえば、購入操作では、在庫を減らさずにユーザーの残高のみが差し引かれます。ステータスの一貫性を保証することは絶対に不可能です。 私たちは皆 MySQL に精通しており、ACID が何であるかも知っていますが、MySQL の ACID はどのように実装されているのでしょうか? アンドゥログやリドゥログがあることは知っていても、なぜそれらがあるのかが分からない場合がありますが、設計の目的が分かると、より明確になります。
事 1
事 2
##begin
始める
部門から * を選択
-
部門(名前)の値("A")に挿入
#- #更新部門セット名 = "B" commit
#commit# ###############################
id name
1 A
2 B
id name
1 B
2 B
でした
原子性
永続性
SQL 更新ステートメントを実行する方法
redo ログ
バッファ プール
binlog
binlog と redo log
update T set c=c 1 where ID=2;
一貫性
概要
以上がインタビュアー: MySQL はどのように ACID を実装しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。