1.トランザクション分離レベル
最初にテーブルを作成します。
#主键命名为number,而不是id,是想和后边要用到的事务id做区别
CREATE TABLE hero (
number INT,
name VARCHAR(100),
country varchar(100),
PRIMARY KEY (number)
) Engine=InnoDB CHARSET=utf8;
INSERT INTO hero VALUES(1, '刘备', '蜀');
同じサーバーに対して、複数のクライアントが接続されている場合があります。各クライアントがサーバーに接続された後、セッション(Session)と呼ばれることがあります。
理論的には、トランザクションが特定のデータにアクセスする場合、他のトランザクションをキューに入れる必要があります。トランザクションがコミットされた後、他のトランザクションは引き続きデータにアクセスできますが、これはパフォーマンスに大きな影響を与えます。また、トランザクションの分離を維持する必要がありますが、同じデータにアクセスする複数のトランザクションを処理するときにサーバーのパフォーマンスを可能な限り高くする必要があります(分離の一部はパフォーマンスの一部と引き換えに犠牲になります)。
1.トランザクションの同時実行で発生する問題
①汚い書き込み:
あるトランザクションが、コミットされていない別のトランザクションによって変更されたデータを変更する場合、それはダーティ書き込みが発生したことを意味します。
その後、セッションBのトランザクションがロールバックされると、セッションAの更新は存在しなくなります。
②ダーティリーディング:
トランザクションが別のコミットされていないトランザクションによって変更されたデータを読み取る場合は、ダーティ読み取りが発生したことを意味します。
③繰り返し不可の読み:
トランザクションがコミットされた別のトランザクションによって変更されたデータのみを読み取ることができ、他のトランザクションがデータを変更してコミットするたびに、トランザクションは最新の値を照会できます。これは、繰り返し不可能な読み取りが発生することを意味します。
④ファントムリーディング:
トランザクションが最初に特定の条件に従っていくつかのレコードを照会し、次に別のトランザクションがこれらの条件を満たすレコードをテーブルに挿入する場合、元のトランザクションが条件に従って再度照会すると、別のトランザクションによって挿入されたレコードも読み取ることができます。これは、ファントム読み取りが発生したことを意味します。
以前に読み取ったが後で読み取ることができないレコードの場合、それは何ですか?
これは、各レコードの繰り返し不可能な読み取りの現象に相当します。ファントム読み取りのみは、前回の読み取りでは取得されなかった読み取りレコードを強調表示します。
2.トランザクションの4つの分離レベル
同時トランザクション実行で発生した問題の重大度で並べ替えます:ダーティ書き込み>ダーティ読み取り>繰り返し不可の読み取り>ファントム読み取り
パフォーマンスの一部と引き換えに分離の一部を放棄することは、ここに反映されます。分離レベルを確立するために、分離レベルが低いほど、問題が発生する可能性が高くなります。
SQL標準で確立された4つの分離レベルがあります
- コミットされていない読み取り:コミットされていない読み取り。
- READ COMMITTED:読み取りがコミットされました。
- 繰り返し可能な読み取り:繰り返し可能な読み取り。
- SERIALIZABLE:シリアル化可能。
分離レベル | ダーティリード | 繰り返し不可の読み取り | 幻覚 |
---|---|---|---|
コミットされていない読み取り | 可能 | 可能 | 可能 |
コミット済みを読む | ありえない | 可能 | 可能 |
繰り返し読む | ありえない | ありえない | 可能 |
シリアル化可能 | ありえない | ありえない | ありえない |
- SERIALIZABLE分離レベルでは、さまざまな問題は発生しません。
- ダーティライティングの問題は深刻すぎます。分離レベルに関係なく、ダーティライティングは発生しません。
- MySQLのデフォルトの分離レベルはREPEATABLEREADです
分離レベルを設定します。
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL level;
/*level: {
REPEATABLE READ
| READ COMMITTED
| READ UNCOMMITTED
| SERIALIZABLE
}*/
2.MVCCの原理
MVCC(Multi-Version Concurrency Control、Multi-Version Concurrency Control)は、READCOMMITTDとREPEATABLEREADの2つの分離レベルを使用して通常のSEELCT操作を実行するときに、記録されたバージョンチェーンにアクセスするプロセスを指します。
1.バージョンチェーン
InnoDBストレージエンジンを使用するテーブルの場合、そのクラスター化インデックスレコードには2つの必要な非表示列が含まれます(row_idは不要であり、作成するテーブルには主キーまたはNULL以外のUNIQUEキーは含まれません。row_id列):
- trx_id:トランザクションがクラスター化インデックスレコードを変更するたびに、トランザクションのトランザクションIDがtrx_id非表示列に割り当てられます。
- roll_pointer:クラスター化インデックスレコードが変更されるたびに、古いバージョンがUNDOログに書き込まれます。この非表示の列は、レコードが変更される前に情報を検索するために使用できるポインターに相当します。
レコードが変更されるたびに、UNDOログが記録され、各UNDOログにもroll_pointer属性があります(レコードには以前のバージョンがないため、INSERT操作に対応するUNDOログにはこの属性がありません)。リンクリストに一緒にリンクされています。レコードが更新されるたびに、古い値が元に戻るログに記録されます。これは、レコードの古いバージョンであっても、更新の数が増えると、すべてのバージョンがroll_pointerによってリンクリストに接続されます。属性、このリンクリストを置くと呼ばれますバージョンチェーン、バージョンチェーンのヘッドノードは、現在のレコードの最新の値です。
2. ReadView
- READ UNCOMMITTED分離レベルを使用するトランザクションの場合、コミットされていないトランザクションによって変更されたレコードを読み取ることができるため、最新バージョンのレコードを直接読み取ることをお勧めします。
- SERIALIZABLE分離レベルを使用するトランザクションの場合、レコードへのアクセスにロックが使用されることが規定されています。
- READCOMMITTEDおよびREPEATABLEREAD分離レベルを使用するトランザクションの場合、コミットされたトランザクションによって変更されたレコードが読み取られることを確認する必要があります。つまり、別のトランザクションがレコードを変更したがまだコミットしていない場合、直接読み取ることはできません。レコードの最新バージョン。
中心的な問題は、バージョンチェーンのどのバージョンが現在のトランザクションに表示されるかを判断する必要があるということです。
この目的のために、ReadViewの概念が提案されています。ReadViewには主に4つの重要なコンテンツが含まれています。
- m_ids: ReadViewが生成されたときに現在のシステムでアクティブだった読み取りおよび書き込みトランザクションを表すトランザクションIDのリスト。
- min_trx_id:ReadViewが生成されたときの、現在のシステムのアクティブな読み取りおよび書き込みトランザクションの最小トランザクションID、つまりm_idsの最小値を示します。
- max_trx_id: ReadViewが生成されたときにシステム内の次のトランザクションに割り当てられる必要があるID値を示します。
max_trx_idはm_idsの最大値ではなく、トランザクションIDは段階的に割り当てられることに注意してください。たとえば、ID 1、2、および3の3つのトランザクションがあり、ID3のトランザクションがコミットされます。次に、新しい読み取りトランザクションがReadViewを生成するとき、m_idsには1と2が含まれ、min_trx_idの値は1であり、max_trx_idの値は4です。
- creator_trx_id:ReadViewを生成したトランザクションのトランザクションIDを示します。
ReadViewを使用して、レコードのバージョンが表示されているかどうかを判断する手順は次のとおりです。
- アクセスされたバージョンのtrx_id属性の値がReadViewのcreator_trx_idの値と同じである場合、現在のトランザクションが独自の変更されたレコードにアクセスしていることを意味するため、現在のトランザクションからこのバージョンにアクセスできます。
- アクセスされたバージョンのtrx_id属性の値がReadViewのmin_trx_id値よりも小さい場合は、現在のトランザクションがReadViewを生成する前に、このバージョンを生成したトランザクションがコミットされていることを示しているため、現在のトランザクションからこのバージョンにアクセスできます。
- アクセスされたバージョンのtrx_id属性の値がReadViewのmax_trx_id値より大きい場合、このバージョンを生成するトランザクションは、現在のトランザクションがReadViewを生成した後に開かれるため、現在のトランザクションからこのバージョンにアクセスできないことを示します。
- アクセスしたバージョンのtrx_id属性値がReadViewのmin_trx_idとmax_trx_idの間にある場合、trx_id属性値がm_idsリストにあるかどうかを判断する必要があります。アクセスできません。そうでない場合は、ReadViewの作成時にバージョンを生成したトランザクションがコミットされ、バージョンにアクセスできることを意味します。
READCOMMITTEDとREPEATABLEREADの分離レベルの非常に大きな違いは、ReadViewを生成するタイミングです。
- READCOMMITTED-各読み取りデータの前にReadViewを生成します
- REPEATABLE READ-初めてデータを読み取るときにReadViewを生成し、このReadViewを後続のクエリ操作に再利用します。
- 主キーを更新するDELETEステートメントまたはUPDATEステートメントを実行すると、対応するレコードがページから完全に削除されることはありませんが、レコードを削除でマークするのと同じ、いわゆる削除マーク操作が実行されます。フラグ。これは主にMVCCサービスを目的としています。
- MVCCは、通常のSEELCTクエリを実行する場合にのみ有効になります。