デッドロックについて少し

これは、デッドロックの原因に関する非常に短い投稿です。

InnoDBトランザクションを使用したロードプロジェクトの多かれ少なかれ、フォームのエラーはいつでも表示されることがあります

「ロックを取得しようとしたときにデッドロックが見つかりました。 トランザクションを再開してみてください»

主なことは、これらの恐ろしい言葉を見てパニックにならないことです。今、私たちはこれがなぜ起こっているのかを理解します。


ロックの種類について少し

ブロックタイプに関するMysqlの公式ドキュメントには、ほとんど書かれていません。

ロックには、共有(S)と排他(X)の2種類があります。 最初のタイプでは、このロックの対象となるデータのみを読み取ることができ、2番目のタイプでは、読み取り、書き込み、削除、および(中程度のサイレント) レベルSロックの取得が可能です。

また、トランザクション#1が行rでタイプSのロックを所有している場合、別のトランザクション#2がこのロックをキャプチャできると言われています。 この行でタイプXロックを取得するには、2番目のトランザクションが静かに待機する必要があります。

トランザクション#1が行rでタイプXロックを所有している場合、トランザクション#2は同じロックをキャプチャすることも、新しいレベルSを取得することもできません。

学習する必要がある重要な点が1つあります。ロックSとXは2つの異なるロックです。 これは、ロックがSであることを意味するのではなく、ロックXのサブセットです。これらは2つの異なるエンティティです。

デッドロックに戻ります。 いくつかのフォーラムで、「Mysqlでデッドロックを取得する方法」という質問に出会いました。 実際には非常に簡単です。

2つのトランザクション、タイプSとXのロック、およびロックが受信される行の2つのトランザクションが用意されています。

1行のデッドロックの簡単なレシピ
1)トランザクション#1はロックSを受け取り、引き続き動作します
2)トランザクション#2はタイプXのロックを取得しようとし、トランザクション#1がロックSを解放すると待機を開始します
3)トランザクション#1はタイプXのロックを取得しようとし、...トランザクション#2がタイプXのロックを取得し、それを解放すると待機を開始します

皿料理

滑りやすい瞬間があります。 同じ行にすでにロックSがある場合、トランザクション#1はロックXを取得できません。 私たちが話すことを妨げるもの
1)まず、XとSは2つの異なるロックです
2)次に、タイプSのロックは、タイプXのロックを受け取る権利を与えません。特権なし-順番に!

上記の状況のコード

トランザクション#1
BEGIN; SELECT * FROM `testlock` WHERE id=1 LOCK IN SHARE MODE; /* GET S LOCK */ SELECT SLEEP(5); SELECT * FROM `testlock` WHERE id=1 FOR UPDATE; /* TRY TO GET X LOCK */ COMMIT; 

トランザクション#2
 BEGIN; SELECT * FROM `testlock` WHERE id=1 FOR UPDATE; /* TRY TO GET X LOCK - DEADLOCK AND ROLLBACK HERE */ COMMIT; 


これに対処するには? オフ。 Mysqlは、より頻繁にコミットし、エラーコードを再確認して、ロールバックされたトランザクションを再送信することをお勧めします。 すぐにタイプXロックを取得するより良いオプションがあるように思えます。その後、レシピの3番目のステップで、トランザクション#1が正当なロックを取得し、静かに終了することができます

最後に、 SHOW ENGINE INNODB STATUSコマンドは、デッドロックの原因を特定するのに役立ちます。デッドロックの原因は、どのロックが保持され、どのロックが待機しているかを示すことです。

Source: https://habr.com/ru/post/J160485/


All Articles