レコードがなかったらINSERTして返すみたいなのをもっと確実にやる
元ネタ
レコードがなかったらINSERTして返すみたいなのを確実にやる | おそらくはそれさえも平凡な日々
http://www.songmu.jp/riji/entry/2014-03-02-find-or-create-surely.html
このソースコードの処理だと
# エラーが発生していて重複エラーだったら取り直す
と
# ロックかけたいときは取り直す
の処理の間に、該当レコードがDELETEされてしまうと
空行にFOR UPDATEしてしまい、ギャップロックの悪夢再び、になってしまうかと。
どうしても確実にやりたい、でも、ON DUPLICATE KEY UPDATEも
INSERT IGNOREも、(元ネタには言及ないけど)REPLACE INTOも嫌!ってことなら
「ロック専用テーブル」を作るのがいいのではないかなと。
処理をかけたいテーブルと同じPKを持つテーブルを作る。(複合キーなら同じく複合で)
このロック専用テーブルには他のカラムは要らない。
で、トランザクションの最初に、
ロック専用テーブルにこれから処理しようとしているデータのPKをINSERT。
↓
本来やりたい処理(レコードがなかったらINSERT)を行う
↓
ロック専用テーブルにINSERTしたデータを削除してからコミット
こうすれば、いけるんじゃないかしら。
並行スレッドは、処理をしようとしても、最初のロック専用テーブルのINSERTに失敗するから
処理できないはず。
一方、ロック専用テーブルにはPKを直接指定してINSERTしてるので
このケースの時はネクストキーロックはかからないんじゃなかったかな。。。ちょっと記憶が曖昧。
実際動作確認したわけじゃないので
嘘書いてたらごめん。
まぁ、このためだけに、一見何も入ってないテーブル
(トランザクション開始時にINSERTして、コミット直前にDELETEしちゃうから)
を作らなきゃいけないってのがうざいので
許容できる状況なら ON DUPLICATE KEY UPDATEがおすすめかな。