MySQLで「Deadlock found when trying to get lock」デッドロック
MySQLで SELECT ・・・ FOR UPDATE で複数行をロックしてから UPDATE すると「Deadlock found when trying to get lock」とエラーが出てデッドロックになった時の話
詳しくは以下の記事にわかりやすくまとめられていました
参考記事:SELECT … FOR UPDATEとUPDATEでデッドロックが出る人へ
MySQLで「Deadlock found when trying to get lock」デッドロック
発生する条件
- MySQL8.0.17以前
- Where句で取得するレコードが複数行(※フルテーブルスキャンに近くなると発生)
- 処理が TRANSACTION 開始 → SELECT ・・・ FOR UPDATE → UPDATE の順で行っている
原因
詳しい発生原因は リリースノート に書かれている
InnoDB: A deadlock was possible when a transaction tries to upgrade a record lock to a next key lock. (Bug #23755664, Bug #82127)
InnoDB: トランザクションがレコード ロックを次のキー ロックにアップグレードしようとすると、デッドロックが発生する可能性がありました。 (バグ #23755664、バグ #82127)
解決方法
解決方法は3つ
MySQLのバージョンを 8.0.18 以降にする
これが一番確実な方法
でも運用中のシステムだと安易にMySQLのバージョンアップできないので断念…
transaction_isolation を REPEATABLE-READ にする
これもシステムに影響するので断念…
SELECT ・・・ FOR UPDATE するレコードを絞る
結局 SELECT ・・・ FOR UPDATE でロックするレコードを可能な限り絞るという方法で対応
対応した解決方法
発生したのは在庫管理システムで起こりました
テーブルとデータ
参考するテーブル構成
MySQL > show create table products\G
*************************** 1. row ***************************
Table: products
Create Table: CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '在庫商品ID',
`amount` int(11) NOT NULL COMMENT '金額',
`saled` datetime DEFAULT NULL COMMENT '売却日時',
PRIMARY KEY (`id`),
KEY `saled` (`saled`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='在庫商品'
1 row in set (0.01 sec)
サンプルデータ
insert into products
(amount, saled)
values
(100, NULL),(110, NULL),(200, NULL),(250, NULL),(500, NULL),
(510, NULL),(535, NULL),(580, NULL),(600, NULL),(650, NULL);
処理
- TRANSACTION を開始
- 在庫商品の中から売れ残っているレコードを SELECT ・・・ FOR UPDATE
- ロックした行から指定個数を UPDATE
- COMMI を実行
対応
上記処理の2の「在庫商品の中から売れ残っているレコードを SELECT ・・・ FOR UPDATE」でロックするレコードを絞りこむ(ただ一意にはできなかった)
在庫で売れ残っているレコードをすべて SELECT していたので、とりあえず 100レコード だけロックするようにしました
対応後の処理
- 在庫で売れ残っているレコードを取得(とりあえず100レコード)
- TRANSACTION を開始
- 在庫から売り出す商品数分の在庫IDを配列へ退避
- 在庫商品の中から売れ残っているレコードを SELECT ・・・ FOR UPDATE
- 退避していた在庫IDを Where句 で指定
- 他のリクエストで先取されていたら もう一度 SELECT ・・・ FRO UPDATE をやり直す
- ロックした行から指定個数を UPDATE
- COMMI を実行
ディスカッション
コメント一覧
まだ、コメントがありません