ホームページ >データベース >mysql チュートリアル >MySQL クロス行トランザクション モデル (詳細な図による説明)
MySQL トランザクション モデルについてはインターネット上にも多くの紹介があり、この記事を書く前に、私も参考として多くの情報を読み、理解を深めようとしました。奥深くて包括的。ほとんどの紹介記事を読んだところ、いくつかの記事が不完全であることがわかりました。たとえば、いくつかの分離レベルでの MySQL のパフォーマンスを紹介するだけで、技術的な観点から説明していない記事もあります。一部の記事は非常に包括的ですが、構成が不十分で、理解するのが簡単ではありません。これが、著者があなたに何か違うものを提供し、技術的な観点から説明し、理解を促進したいと考えているものです。
トランザクション アトミック性では、トランザクション内の一連の操作が完全に完了するか、操作がまったく実行されないことが必要であり、半分だけを実行することはできません。当時の。 HBase での行レベルのトランザクションのアトミック実装が比較的単純であるのと同様に、アトミック操作のアトミック実装も簡単です。ただし、複数のステートメントで構成されるトランザクションの場合、トランザクションの実行中に例外が発生した場合、アトミック性を確保する必要がある場合、唯一の選択肢は、トランザクションがまったく発生していないかのように、トランザクション開始前の状態にロールバックすることです。全て。これを達成するにはどうすればよいでしょうか?
MySQL のロールバック操作の実装は完全にアンドゥ ログに依存しています。もう 1 つ、アンドゥ ログは MySQL でアトミック性の保証を達成するためだけでなく、以下で説明する MVCC の実装にも使用されます。 Undo を使用してアトミック性を実現します。データを操作する前に、変更前のデータが Undo ログに記録されてから、実際の変更が行われます。例外が発生し、ロールバックが必要な場合、システムは元に戻すときにバックアップを使用して、データをトランザクション開始前の状態に復元できます。次の図は、MySQL のトランザクションを表す基本的なデータ構造です。undo に関連するフィールドは、insert_undo と update_undo で、それぞれ、このトランザクションによって生成された Undo ログを指します。
トランザクション ロールバックは、update_undo (または insert_undo) に基づいて対応する undo ログを検索し、その逆の操作を実行します。削除対象としてマークされたデータの場合は、マークをクリーンアップして削除し、更新されたデータの更新を直接ロールバックします。挿入操作は少し複雑になり、データを削除するだけでなく、関連するクラスター化インデックスおよびセカンダリ インデックス レコード。
UNDO ログは MySQL カーネルの非常に重要なコンテンツです。これには多くの知識が含まれており、次のような複雑です:
1. Undo ログはデータの前に保存する必要があります。 UNDO ログの永続性には、停止例外を防ぐために REDO を記録する必要はありませんか?必要に応じて、ダウンタイムの回復が必要になります...
2. アンドゥ ログを使用して MVCC を実装するにはどうすればよいですか?
3. どのようなシナリオで、これらの UNDO ログをリサイクルしてクリーンアップできますか?掃除方法は?
書き込み同時実行の実装メカニズムは、2 フェーズ ロック プロトコルを使用して対応するレコードに行ロックを追加する HBase のメカニズムと何ら変わりません。ただし、MySQL の行ロック メカニズムは比較的複雑であり、行レコードが主キー インデックスであるか、一意のインデックスであるか、非一意のインデックスであるか、インデックスなしであるかによって、さまざまなロック状況が発生します。
1. id カラムが主キー インデックスの場合、MySQL はクラスター化インデックス レコードのみをロックします。
2. id カラムが唯一のセカンダリ インデックスである場合、MySQL はセカンダリ インデックスのリーフ ノードとクラスター化インデックス レコードをロックします。
3. id 列が一意でないインデックスの場合、MySQL は条件 (id = 15) を満たすすべてのセカンダリ インデックス リーフ ノードと、対応するクラスター化インデックス レコードをロックします。
4. ID 列にインデックスが作成されていない場合、SQL はクラスター化インデックスのフル テーブル スキャンを実行し、フィルタリングのためにスキャン結果を SQL Server レイヤーにロードします。そのため、SQL Server レイヤーの場合、InnoDB は最初にロックを追加します。フィルターが条件を満たさない場合、InnoDB はロックを解放します。したがって、InnoDB はスキャンされたすべてのレコードをロックすることになりますが、これは恐ろしいことです!
RC、RR、またはシリアル化のいずれであっても、上記のメカニズムは書き込み同時実行制御に使用されるため、詳細については説明しません。次に、RC および RR 分離レベルでの読み取りおよび書き込みの同時実行制御メカニズムの分析に焦点を当てます。
RC と RR を詳しく紹介する前に、まず MySQL に MVCC メカニズムを導入する必要があります。これは、RC と RR の両方が MVCC メカニズムを使用してトランザクション間の読み取りおよび書き込みの同時実行性を実現するためです。両者には実装の詳細にいくつかの違いがあるだけで、具体的な違いについては次に説明します。
MySQL の MVCC
最初の 4 つの列は、行に記録されている実際の列の値です。注目する必要があるのは、2 つの非表示列 DB_TRX_ID と DB_ROLL_PTR (ユーザーには表示されません) です。このうち、DB_TRX_ID は行を変更するトランザクションのトランザクション ID を表し、DB_ROLL_PTR は行のロールバック セグメントへのポインタを表し、この行に記録されるすべてのバージョン データは、UNDO のリンク リストの形式で編成されます。実際には、undo.レコードのリンクされたリストの行の履歴を指します。
ここで、データ行を変更するトランザクション trx2 があり、行レコードが次の図のように変化すると仮定します。DB_TRX_ID は、最近行を変更したトランザクションのトランザクション ID (trx2) です。 DB_ROLL_PTR は、UNDO 履歴レコードのリンク リストを指します:
MySQL 行レコードを理解した後、トランザクションの基本構造を見てみましょう。次の図はトランザクションです。上で説明した MySQL のデータ構造。トランザクションが開始されると、トランザクション関連情報、ロック情報、アンドゥ ログ、および非常に重要な read_view 情報を保存するデータ構造が作成されます。
read_view は、下の図に示すように、現在のトランザクションが開始されると、MySQL 全体のすべてのアクティブなトランザクションのリストを保存します。現在のトランザクションが開始されると、システム内のアクティブなトランザクションには、trx4、trx6、 trx7とtrx10。さらに、up_trx_id は、現在のトランザクションが開始されたときの現在のトランザクション リスト内の最小のトランザクション ID を表し、low_trx_id は、現在のトランザクションが開始されたときの現在のトランザクション リスト内の最大のトランザクション ID を表します。
read_view は、MVCC の実装における重要なポイントであり、現在のトランザクションに表示されるレコードのバージョンを決定するために使用されます。現在のトランザクションがレコードの特定の行を読み取る必要があり、行レコードのバージョン番号 (トランザクション ID) が trxid である場合:
1. trxid
2. trxid > low_trx_id の場合は、行が存在するトランザクションが現在のトランザクションの作成後にオープンされたため、行レコードは現在のトランザクションには表示されないことを意味します。
3. up_trx_id
次の行レコードを例にとると、この行レコードには複数のバージョン (trx2、trx5、trx7、trx12) があり、そのうち trx12 が最新バージョンです。現在のトランザクションに表示される行のバージョンを確認します。
1. この行に記録されている最新バージョンは trx12 です。現在のトランザクション read_view と比較すると、trx12 が現在アクティブなトランザクション リスト内の最大のトランザクション trx10 よりも大きいことがわかります。現在のトランザクションが作成された後に開かれるため、非表示になります。
2. 行レコードの 2 番目に新しいバージョンが trx7 であることを確認します。現在のトランザクション read_view と比較すると、trx7 が現在アクティブなトランザクション リストの最小トランザクション ID と最大トランザクション ID の間にあることがわかります。は、現在のトランザクションが作成されたときに行レコードがアクティブであったことを示します。アクティブ リストを調べると、trx7 が存在することがわかりました。これは、トランザクションがまだ送信されていないため、現在のトランザクションには表示されないことを示しています。
3. 引き続き、レコードの 3 番目の最新バージョン trx5 を表示します。これも、現在のアクティブなトランザクション リストの最小トランザクション ID と最大トランザクション ID の間にあり、行レコードが含まれるトランザクションであることを示しています。現在のトランザクションが作成されたときに、現在のトランザクション内にありました。アクティブなステータスですが、トラバーサルにより、このバージョンがアクティブなトランザクション リストにないことがわかり、trx5 に対応するトランザクションが送信されたことがわかります (注: トランザクション間に相関関係はありません)送信時間とトランザクション番号。トランザクション番号が大きいトランザクションが最初に送信され、トランザクション番号が小さいトランザクションが後で送信される可能性があります。コミット)、そのため、trx5 バージョンの行レコードが現在のトランザクションに表示され、直接返されます。
和RC模式不同,RR模式下事務不會再每次執行select的時候產生最新的read_view,而是在事務第一次select時就產生read_view,後續不會再變更,直至當前事務結束。這樣可以有效避免不可重複讀,使得當前事務在整個事務過程中讀到的資料保持一致。示意圖如下:
這個就很容易理解,三次查詢所使用的全域活躍事務清單都一樣,且都是第一次產生的read_view,那之後查到的記錄必然和第一次查到的記錄一致。
如果對幻讀還不了解的話,可以參考系列的第一篇文章。如下圖所示,1號事務對針對id>1的過濾條件執行了三次查詢,2號事務執行了一次插入,插入的記錄剛好符合id>1這個條件。可以看出來,三次查詢得到的資料是一致的,這個是由RR隔離等級的MVCC機制保證的。這麼看來,是避免了幻讀,但在最後1號事務在id=2處插入一筆記錄,MySQL會回傳Duplicate entry的錯誤,可見避免了幻讀是一種假象。
之前提到的所有RR層級的select語句我們稱為快照讀,快照讀能夠保證不可重複讀,但並不能避免幻讀。於是MySQL又提出」目前讀」的概念,常見的目前讀語句有:
1. select for update
2. select lock in share mode
3. update / delete
並且規定,RR層級下目前讀取語句會為記錄加上一種特殊的鎖定-Gap鎖, Gap鎖並沒有鎖定某個特定的記錄,而是鎖定記錄與記錄之間的間隔,確保這個間隔中不會插入新的其他記錄。下圖是示意圖:
上圖中1號交易首先執行了一個目前讀的select語句,這個語句會在id > 0的所有間隔加上Gap鎖,接下來2號交易在id = 3處執行插入時系統就會回傳Lock wait timeout execcded的例外狀況。當然,其他事務可以在id
Serialization隔離級別是最嚴格的隔離級別,所有讀取請求都會加上讀鎖,不分快照讀和目前讀,所有寫會加上寫鎖。當然,這種隔離等級的效能因為鎖開銷而相對最差。
MySQL事務持久化策略和HBase基本上相同,但是涉及的元件相對比較多,主要有doublewrite、redo log以及binlog:
1. MySQL資料持久化(DoubleWrite)
實際上MySQL的真實資料寫入分為兩次寫入,一次寫入到一個稱為DoubleWrite的地方,寫成功之後再真實寫入資料所在磁碟。為什麼要寫兩次?這是因為MySQL資料頁大小與磁碟一次原子操作大小不一致,有可能會出現部分寫入的情況,例如預設InnoDB資料頁大小為16K,而磁碟一次原子寫入大小為512位元組(磁區大小) ,這樣一個資料頁寫入需要多次IO,這樣一旦中間發生異常就會出現資料遺失。另外要注意的是DoubleWrite效能並不會影響太大,因為寫入DoubleWrite是順序寫入,對效能影響來說不是很大。
2. redolog持久化策略(innodb_flush_log_at_trx_commit)#
##redolog是InnoDB的WAL,資料先寫入redolog並落盤,再寫入更新到bufferpool。 redolog的持久化策略和HBase中hlog的持久化策略一致,預設為1,表示每次事務提交之後log就會持久化到磁碟;該值為0表示每隔1秒鐘左右由非同步執行緒持久化到磁碟,這種情況下MySQL發生宕機有可能會遺失部分資料。值為2表示每次交易提交之後log會flush到作業系統緩衝區,再由作業系統異步flush到磁碟,這種情況下MySQL發生宕機不會遺失數據,但機器宕機有可能會遺失部分數據。3. binlog持久化策略(sync_binlog)#
binlog作為Server層的日誌系統,主要以events的形式順序紀錄了資料庫的各種操作,同時可以紀錄每次作業所花費的時間。在MySQL官方文件上,主要介紹了Binlog的兩個最基本核心作用:備份和複製,因此binlog的持久化會一定程度影響資料備份和複製的完整性。和redo持久化策略相同,可取值有0,1,N。預設為0,表示寫入作業系統緩衝區,異步flush到磁碟。該值為1表示同步寫入磁碟。為N則表示每寫N次作業系統緩衝就執行一次刷新操作。
總結一下,本文是資料庫事務系列文章的第三篇,核心介紹了MySQL的單機跨行事務模型,其中對隔離性所涉及到的鎖定技術、MVCC機制進行了比較詳細的說明。對事務原子性、持久性等相關特性也進行簡單的分析與說明。接著筆者將會帶大家一起聊聊分散式事務模型,看看和單機事務模型到底有何差別。
推薦學習:MySQL教學
以上がMySQL クロス行トランザクション モデル (詳細な図による説明)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。