6件のコメント

@hmatsu47

良い記事を探すことができなかったので自分が書いた記事の宣伝みたいになってしまいますが、sys.innodb_lock_waits ビューで順を追って確かめてみてはいかがでしょう?

https://qiita.com/hmatsu47/items/607d176e885f098262e8

※GA 前に書いたものですが、8.0.13 で同ビューから参照している performance_schema 内の data_locksdata_lock_waits テーブルに変更が入っているので、もしかすると表示内容が少し変わっているかもしれません(未確認)。

(本家リファレンスマニュアル)

https://dev.mysql.com/doc/refman/8.0/en/sys-innodb-lock-waits.html https://dev.mysql.com/doc/refman/8.0/en/data-locks-table.html https://dev.mysql.com/doc/refman/8.0/en/data-lock-waits-table.html

@hmatsu47

すみません、箇条書きにするのを忘れて↑の末尾のリンクが読みにくくなってしまいました。

@hmatsu47

原因、なんとなくわかりました。

トランザクション 1 の SELECT ~ FOR UPDATE は、「次に来る UPDATE のためにロックを取る」のであって、次に来るのが INSERT の場合、INSERTSELECT ~ FOR UPDATE とは別のロックを取ろうとするんですね。

再現 1 の例の場合は、

  1. トランザクション 1 が SELECT ~ FOR UPDATEid=20 に対して排他ロックを取る
  2. トランザクション 2 が SELECT ~ FOR UPDATEid=20 に対して排他ロックを取ろうとして待たされる
  3. トランザクション 1 が INSERTid=20 に対してさらに排他ロックを取ろうとしてデッドロックを検出する

という流れです。

このあたり、↑のコメントで触れたビュー・テーブルを使って、ちょっと記事を書いてみようかと。

@hmatsu47

書き忘れたので追記。3. で id=20 に対して UPDATE を掛ける場合は、意図通りの動作になります(デッドロックにはなりません)。

@hmatsu47

コメント欄を荒らしてすみません。

記事にしました。

https://qiita.com/hmatsu47/items/b49bc18d49da5c6029e5

@bluexxsun

@hmatsu47 とんでもなく返答が遅れてしまってすみません... 私の記事に関して考察して頂いてありがとうございます!