デッドロックケース6

出典:パブリックアカウントyangyidba


I.はじめに

デッドロックは、実際には非常に興味深く、やりがいのある技術的な問題です。おそらく、すべてのDBAと一部の開発学生は、作業の過程でデッドロックに遭遇するでしょう。デッドロックについては、デッドロックを理解したい友達を助けたいと思い、一連のケーススタディを書き続けていきます。

2.ケース分析

2.1環境の説明

MySQL5.6.24トランザクション分離レベルはRRです

create table tx (
  id int not null primary key auto_increment ,
  c1 int not null default 0,
  c2 int not null default 0,
  key idx_c1(c1)
) engine=innodb ;
insert into tx values(24,3,4),(25,3,4),
(26,3,4),(30,5,8);

2.2テストケース

2.3デッドロックログ

----------------------------------
LATEST DETECTED DEADLOCK
------------------------
2018-03-27 15:40:40 0x7f75cafce700
*** (1) TRANSACTION:
TRANSACTION 1850, ACTIVE 20 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)
MySQL thread id 379040, OS thread handle 140143994337024, query id 1521958 localhost root updating
update tx set c2=8 where c1=5
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 27 page no 3 n bits 72 index PRIMARY of table `test`.`tx` trx id 1850 lock_mode X locks rec but not gap waiting
*** (2) TRANSACTION:
TRANSACTION 1849, ACTIVE 32 sec updating or deleting, thread declared inside InnoDB 4999
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 379016, OS thread handle 140143893473024, query id 1521976 localhost root updating
delete from tx where id=30
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 27 page no 3 n bits 72 index PRIMARY of table `test`.`tx` trx id 1849 lock_mode X locks rec but not gap
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 27 page no 5 n bits 72 index idx_c1 of table `test`.`tx` trx id 1849 lock_mode X locks rec but not gap waiting
*** WE ROLL BACK TRANSACTION (1)

2.4デッドロックログを分析する

最初に理解することは、同じフィールドにロックを適用するにはキューイングが必要であることです。

次に、テーブルtyのインデックスidx_c1は、一意ではない通常のインデックスです。トランザクション実行の時系列に従って説明します。これは、理解しやすいものです。

T1:sess2は、更新操作の選択を実行して、レコードID = 30のプライマリキー行ロックを保持します:テーブルtest.txのPRIMARY lock_mode Xはrecをロックしますが、ギャップはロックしません

T2:sess1ステートメントの更新は通常のインデックスidx_c1を介してc2を更新し、最初にXロックlock_modeを取得しますがidx_c1 c1 = 5のギャップは取得しません。次に、プライマリキーid = 30に対応する行ロックを適用しますが、sess2はすでにプライマリキーの行ロックを保持しています。 、したがって、sess1は待機します。

T3:sess2は、プライマリキーid = 30に基づいてレコードを削除し、id = 30の行ロックとc1 = 5のインデックス行ロックを申請する必要があります。ただし、sess1とロックを保持しているため、テーブルtest.tx trx id 1849のインデックスidx_c1はrecをロックしますが、ギャップ待機はロックしません。

sess2(delete)はsess1(update)を待機し、sess1(update)はsess2(select for update)がループで待機するのを待機し、デッドロックを引き起こします。

RDBMSシステムのデッドロックの根本的な原因は、次のように要約できます。トランザクションロックシーケンスが異なると、循環待機が発生し、デッドロックが発生します。

2.5ソリューション

sess1の更新を変更して、プライマリキーに基づいて更新します。つまり、tx set c2 = x(id = 30)を更新し、ロックモードをシーケンシャルロックに変更し、プライマリキーIDのロックを適用し、相互の保持のクロスロックと相互適用を回避します。ロック。

3、まとめ

上記の場合のデッドロックは、異なるセッションが共通のインデックスidx_c1とプライマリキーをめぐって互いに競合するためです。これにより、ループの待機が原因でデッドロックが発生します。実稼働プロセスで同じ行を更新する際に高い同時実行性が発生した場合は、デッドロックを回避するために、異なるインデックスを介した更新を回避することを検討してください。

拡張読書

全文は終わりました。

MySQLをお楽しみください:)

TeacherYeの「MySQLCoreOptimization」クラスがMySQL8.0にアップグレードされました。コードをスキャンして、MySQL8.0の練習の旅を始めてください。

おすすめ

転載: blog.csdn.net/n88Lpo/article/details/108806208