












トランザクションの分離レベルはデータベースの並行制御の核心であり、トランザクション間の分離方法や、一つのトランザクションが他のトランザクションの変更をどの程度見ることができるかを定義しています。本稿では sql_store データベースを基に、コード例を通じてMySQLがサポートする4種類の標準的なトランザクション分離レベルとその影響を詳細に解説し、シナリオを用いて分離レベルの役割を説明し、死锁問題とその回避方法を解析することで、読者がトランザクションの並行管理を深く理解するのを助けます。
学習内容
1. トランザクション分離レベルの概要
MySQLは4種類の標準的なトランザクション分離レベルをサポートしており、低い順に以下の通りです:
隔離レベルが高いほど、並列性能は低くなりますが、データ整合性は高くなります。ATM 転账シナリオでは、適切な隔離レベルを設定することで、口座残高の更新が他のトランザクションによって干渉されないように保証できます。
2. 隔離レベルの確認と設定
SHOW VARIABLES LIKE 'transaction_isolation' で現在の隔離レベルを確認し、デフォルトでは REPEATABLE-READ__が表示されます。以下のステートメントを使用して隔離レベルを設定できます:
3. 並行問題と隔離レベル
異なる隔離レベルは汚染読み取り、不整合読み取り、幻読み取りの制御能力が異なります:
4. 死锁
死锁は、並行トランザクションで複数のトランザクションがお互いのリソースを解放するのを待っている状態で、実行を続けることができない状態です。MySQL は死锁を検出し、一つのトランザクションを終了させ、エラーメッセージを表示します。死锁を減らすには、一貫したリソースアクセス順序を保つか、トランザクションの長さを短くすることが必要です。
サンプルコードと解説
1. 隔離レベルの確認
ショー 変数 のよう 'transaction_isolation';
は現在の分離レベルを表示し、デフォルト値は REPEATABLE-READであり、MySQL InnoDBの標準設定です。
2. 分離レベルの設定
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
は現在のセッションの分離レベルを SERIALIZABLEに設定し、以降のトランザクションを順次実行させ、すべての並行問題を回避します。
3. 読み取り未コミット(READ UNCOMMITTED)
コンソール 1:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT points FROM 顧客 WHERE 顧客ID = 1;
コンソール 2:
START TRANSACTION;
UPDATE 顧客 SET ポイント = 20 WHERE 顧客ID 1;
-- 未コミット
でコンソール1で READ UNCOMMITTED を設定した後、顧客1のポイント(元は2303)をクエリします。コンソール2はポイントを20に更新しコミットせず、コンソール1が再度クエリすると20が表示され、汚染読み取りが現れます。もしコンソール2がロールバックされると、コンソール1のクエリ結果は無効になり、業務判断を誤引导する可能性があります。
4. 読み取りコミット(READ COMMITTED)
コンソール1:
SET TRANSACTION ISOLATION レベル 読み取り コミット済み;
SELECT ポイント FROM 顧客 WHERE 顧客ID = 1;
コンソール 2:
START トランザクション;
UPDATE 顧客 SET ポイント = 20 WHERE 顧客ID
= 1;
コミット;
コンソール 1 で READ コミットテッド を設定した後、ポイントをクエリします。コンソール 2 で変更がコミットされていない場合、コンソール 1 は元の値 2303 をまだ見ることができ、汚染読みを防ぎます。コンソール 2 がコミットされると、コンソール 1 はクエリして 20 を取得します。しかし、同じトランザクション内で複数回クエリした場合、他のトランザクションがコミットされることで結果が一貫しなくなり、不重複読みが発生する可能性があります。
コンソール 1(再読み出し不可の例):
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT points FROM customers WHERE customer_id = 1;
-- 戻り値 20
SELECT points FROM customers WHERE customer_id = 1;
-- 戻り値 30
COMMIT;
コンソール 2:
START TRANSACTION;
UPDATE customers SET points = 30 WHERE customer_id
= 1;
COMMIT;
コンソール1 最初のクエリで20が取得され、コンソール2でコミット後に更新され30になる、コンソール1の2回目のクエリで30が取得され、不重複読み取りが現れ、データの整合性が影響を受ける。
5. 複数回読(REPEATABLE READ)
コンソール 1:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT points FROM 顧客 WHERE customer_id = 1;
-- 30を返します
SELECT points FROM 顧客 WHERE customer_id = 1;
-- まだ30を返します
コミット;
コンソール 2:
スタート トランザクション;
アップデート customers セット points = 40 ウェhre customer_id
= 1;
コミット;
において 一貫性読み取り の下、コンソール1ではトランザクション開始時に一貫性の視点が作成され、トランザクション開始時のスナップショットに基づいています(積分は30です)。コンソール2では変更が40にコミットされますが、コンソール1の2回目のクエリではまだ30が返され、不整合読み取りを回避します。MVCCはトランザクション内のデータの一貫性を保証します。
幻読の例:
コンソール1:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
トランザクションを開始 ;
* を customers から選択 して、 stateが
'CO'のものをフィルタリング
コミット
;:
開始 TRANSACTION;
UPDATE customers SET state = 'CO' WHERE customer_id
= 1;
COMMIT;
コンソール 1 検索 state = 'CO' の顧客は初期状態で1件の記録しかありません。コンソール2で顧客1の状態を'CO'に変更し、コミットします。コンソール1がトランザクションをコミットした後再度クエリを実行しても、依然として1件の記録しか返されず、データベースの最新状態が反映されません。これにより幻読が発生します。InnoDBの隙間ロックは幻読を部分的に緩和できます。
6. 串行化(SERIALIZABLE)
コンソール1:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT * FROM customers WHERE state = 'CO';
COMMIT;
コンソール 2:
START TRANSACTION;
UPDATE customers SET ステート = 'CO' どこに カスタマーID 2;
コミット
において SERIALIZABLE 下で、コンソール1をクエリします state = 'CO' 顧客(初期2件)。コンソール2は顧客2の状態を'CO'に変更しようと試みましたが、コミットできませんでした。コンソール1のトランザクションはコンソール2のコミットを待ってブロックされ、幻読を防ぎます。コミット後、コンソール1は最新のデータを正確に反映します。
7. 死锁
コンソール 1:
START TRANSACTION;
UPDATE customers SET state = 'VA' WHERE customer_id
= 1;
UPDATE orders SET status = 1 WHERE order_id
= 1;
COMMIT;
コンソール 2:
START TRANSACTION;
UPDATE orders SET status = 1 WHERE order_id
= 1;
UPDATE customers SET state = 'VA' WHERE customer_id
= 1;
COMMIT;
コンソール 1 ロック customers の行で、 ordersをロックしようと試み、コンソール2が ordersをロックし、 customersをロックしようとするが、循環依存を形成し、デッドロックを引き起こす。MySQLはデッドロックを検知すると、一つのトランザクションを終了し、エラーメッセージを表示する。デッドロックを回避するには、リソースアクセス順序を統一するか、トランザクション長を短縮する必要がある。
は
トランザクションの分離レベルが並行トランザクションのデータの可視性と一貫性を決定する。READ UNCOMMITTED は性能が高いがリスクが大きく、SERIALIZABLE は安全だが性能が低く、REPEATABLE READ はMySQL InnoDBのデフォルトの妥協案である。ATM转账シナリオは分離レベルがデータの一貫性に与える重要性を示している。本稿は sql_store データベース、コード例を通じて四つの隔離レベルと死锁問題を解析します。後続のコンテンツでは、インデックス設計やクエリ最適化について探求し、ご注目ください。
このコンテンツは慣性聚合(RSSリーダー)によって自動集約されています。参考としてご覧ください。 原文出典 — 著作権は原著者に帰属します。