インタビューと非難シリーズ-トランザクション分離レベル

Xiao Zhangはインタビューに駆けつけましたが、インタビュアーに殴られました!

Xiao Zhang:こんにちは、インタビュアー。私は面接のためにここにいます。

インタビュアー:こんにちは、シャオ・チャン。MySQLデータベースに堪能なあなたの履歴書を読みました。それでは、事件を知る必要がありますが、事件の特徴 について話していただけます か?

Xiao Zhang:トランザクションには4つの特性、つまりACIDがあります。

  • Atomicity: トランザクション開始後のすべての操作(すべて成功またはすべて失敗)。

  • 一貫性: トランザクションの前後のデータベースの整合性制約は破棄されません。たとえば、AがBに送金した場合、Aがお金を差し引くことは不可能であり、Bはお金を受け取りません。

  • 分離:複数のトランザクションに同時にアクセスすると、トランザクションが分離されます。

  • 耐久性:トランザクションが完了した後、データベースでのトランザクションの操作はデータベースに保存され、ロールバックできません。

インタビュアー:まあ、答えは正しいです。では、トランザクションの分離レベルは何ですか?

Xiao Zhang:トランザクション分離レベルの高さから低さまで4つの分離レベルがあります。つまり、シリアル化(SERIALIZABLE)、反復可能読み取り(REPEATABLE READ)、読み取りコミット(READ COMMITTED)、読み取り非コミット(READ UNCOMMITTED)です。

インタビュアー:では、これら4つの分離レベルによって引き起こされる問題について話していただけますか?

(張笑うので、聞きたいと思いますが、幸いなことに、私は通常、公開番号のJAVA Rizhilu」に焦点を当てています)

Xiao Zhang:わかりました、インタビュアー。

データベースがREADUNCOMMITTED分離レベルを使用している場合、 ダーティリードが発生し ますトランザクションは送信される前に他の人に見られる可能性があるため、読み取ったデータが最終データである保証はありません。他の誰かがトランザクションをロールバックすると、ダーティデータの問題が発生します。

読み取りコミット(READ COMMITTED)は、トランザクションが他のトランザクションによってコミットされたデータのみを読み取ることができるため、ダーティ読み取りの問題は発生しませんが、「繰り返し不可能な読み取り 」の問題が発生することを意味しますたとえば、トランザクションAは人の名前をZhangSanからLiSiに変更し、トランザクションBはトランザクションAがコミットする前にZhang Sanを読み取りますが、トランザクションAがコミットするとLiSiになります。

繰り返し可能読み取り(REPEATABLE READ):繰り返し可能読み取りは、READ COMMITTEDによって引き起こされる繰り返し不可能な読み取りの問題を解決することです。つまり、データが送信された場合でも、トランザクションは他のトランザクションによる既存のデータの変更を読み取りません。つまり、トランザクションの開始時に読み取られるものであり、トランザクションがコミットされる前はいつでもデータは同じです。繰り返し不可能な読み取りの問題は解決しますが ファントム読み取りの 問題が発生します。たとえば、トランザクションAがZhangSanをLiSiに変更し、トランザクションBがLi Siという名前のユーザーを挿入します。このとき、トランザクションAはLi Siという名前のユーザーを探し、余分な1つと2つのLiSiが表示されていることを検出します。ファントムリーディングです。

シリアル化(SERIALIZABLE):上記のすべての問題を解決しますが、効率が最も低く、トランザクションの実行を順次実行に変えます。

インタビュアー:答えは良いです。MySQLのデフォルトの分離レベルを知ってい ますか?

シャオチャン:MySQLのデフォルトの分離レベルは、REPEATABLE READ Oracleが使用しているが、READ COMMITTEDが

インタビュアー:しかし、MySQLを使用する場合、幻の読み物はありません。どうすればそれを解決できますか?

Xiao Zhangは汗を拭き、少し緊張しました。ええと、InnoDBは主にロックを使用して、ファントム読み取りの問題を解決します。

インタビュアー:はい、それはロックです、それでそれを達成する方法は?

Xiao Zhang:私は...突然何か問題が発生したので、最初に戻ります。

インタビュアー:InnoDBがファントム読み取りをどのように解決するかを理解するには、最初にInnoDBが持つロックの種類を知る必要があります。

  • レコードロック:単一行レコードのロック

  • ギャップロック:ギャップロック、レコード自体ではなく範囲をロックし、左オープンと右クローズの原則に従います

  • Next-Key Lock:GapLockとRecordLockを組み合わせて、範囲をロックし、レコード自体をロックします。解決すべき主な問題は、REPEATABLEREAD分離レベルでのファントム読み取りです。

一意のインデックスに移動すると、Next-KeyLockはRecordLockにダウングレードされます。つまり、範囲ではなく、インデックス自体のみがロックされます。つまり、Next-Key Lockの前提条件は、一意でないインデックスとプライマリキーインデックスであり、トランザクション分離レベルはRRであり、クエリインデックスが取得されます。

以下では、特定の例を使用して、上記のファントム読み取りの問題をシミュレートします。

CREATE TABLE T (id int ,name varchar(50),f_id int,PRIMARY KEY (id), KEY(f_id)) ENGINE=InnoDB DEFAULT CHARSET=utf8
insert into T SELECT 1,'张三',10;
insert into T SELECT 2,'李四',30;

InnoDBは、行レコードをすばやく見つけるために、データベース内のインデックス用のB +ツリーのセットを維持します。B +インデックスツリーは順序付けられているため、このテーブルのインデックスはいくつかの間隔に分割されます。

トランザクションAは次のステートメントを実行し、ZhangSanをLiSiに変更する必要があります。

select * from t;
update t set name = '李四' where f_id = 10;

現時点では、SQLステートメントは一意でないインデックスを使用しているため、Next-Key Lockロックを使用すると、f_10 = 10の行に行ロックが追加されるだけでなく、このレコードの両側にギャップロックが追加されます。つまり(-∞、10] 、(10、30]ギャップロックがこれらの2つの間隔に追加されます。

このとき、トランザクションBが次のステートメントを実行しようとすると、エラーが報告されます。[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

INSERT INTO T SELECT 3,'王五',10;  -- 满足行锁,执行阻塞
INSERT INTO T SELECT 4,'赵六',8;   -- 满足间隙锁,执行阻塞
INSERT INTO T SELECT 5,'孙七',18;  -- 满足间隙锁,执行阻塞

唯一のトランザクションレコードのAの提出を待つF_ID = 10の必要性を挿入しないでf_id <1010< f_id <30記録が完了することができず、以上のレコード30は影響を受けません、ファントム読み取りの問題を解決するのに十分です。

今お話ししたのは、f_idがインデックス列の場合です。f_idがインデックス列でない場合はどうなりますか?

このとき、データベースはテーブル全体にギャップロックを追加します。したがって、インデックスがない場合、f_idが30以上であるかどうかに関係なく、トランザクションAが正常に挿入される前に、トランザクションAがコミットされるのを待つ必要があります。

インタビュアー:さて、友人、あなたは事件の孤立レベルのインタビューポイントについて明確ですか?あなたのインタビューがこの質問に困惑しないことを願っています〜

Xiao Zhang:学んだ後、次回また来ます。(すぐに戻って、履歴書のマスタリーデータベースを削除してください。)

上記、私はあなたを助けたいと思っています!


 

 

おすすめ

転載: blog.csdn.net/jianzhang11/article/details/112792020