存在しないレコードにもロックがかかるってこのことか!?なんのために?うーん...とにかくちょっと広めのロックを取得していると。Read」事件が発生するという面もあり、(この件は、別の記事でまた書きましょう)もろもろ実現するために、なにかと幅を広げて対応しているのかも。そのロジックはちょっと正確にはなかなか追跡できていません。したらデッドロックが起きたか?さて、特徴を知ったところでここからが本題。「待つ」だけならまあまだいいよね。そりゃぁ、場合によってはデッドロック発生しちゃうかもだけど、レアケースであればさ、クリティカル業務でなければさ。怖がれる事象があるのです。見えないものへのロックって物理的なものへのロックと違うの!?わからんとしかいいようがないけど、とにかくこの実験が言えること:子テーブルの更新を「delete/insert」方式で実装すると、わりと簡単にデッドロックが発生しちゃうということ。「論理削除update/insert」でも全く同じ。してから、batchInsert()。いちいち事前selectして0件以上だったらdeleteってやらない。0件ならdeleteやupdateが単に空振りすればいいだけだから。MySQLだと0件時のチェックしてあげないとデッドロックする。同じ親レコードであれば、排他制御を先にやることで更新で後が待つ。dfpropの設定次第で、内部的にselectCount()して0件時は実行しないってオプションを追加したけど、それもなんかなぁと。事前検索入ってしまう。世の中、なんとかうまくいっちゃってるんでしょう。実際に現場で見てしまいました。実運用で発生したのを...JUnitのテストで再現DBFluteのExampleにて、同じような処理で再現しています。found"));しかしながら、これがまた不安定な動きするんです。件削除状態にしておけば、発生する。【追記】補足をブログ最後に追記そういえば参考のブログで検証されていたのは、主キー(PK)のカラムです。PKのカラムとそれ以外のカラムでは動きが違いそう。方で、存在しない未来の会員ID「99999」で空振り削除してみました。found"));これもデッドロック!参考にしたブログのパターンとはちょっと違って、Identityで自動採番されるPKで、かつ、次のレコードが存在しない値を指定して空振りの更新ロック取得してみました。これが、「-1」で空振りしてもデッドロックは発生しません。【追記】補足をブログの最後に追記すいません...推測にもなってないですけど...要は実験結果ですね。実験もこれ以上細かくやるのはさすがにというところでここまで。ユニークインデックスの方は、あまり問題になることはないかと。圧倒的に問題なのは普通のインデックス、FKカラムのときです。方式、MySQLではちょっと鬼門になりそうです。その後の、追記たち【追記】PURCHASEテーブルのMEMBER_IDはFK制約が貼ってあるので、同時にNON-UNIQUEインデックスが付与されています。PURCHASE_DATETIMEの三つからなる複合ユニークインデックスが貼られています。テストは、デッドロックが発生しなくなりました。同じ会員ID同士で実行させるとやはり発生しました。そのまま待ち続けてくれれば別にいいのに...)つまり、どちらでも発生はするんだけど、複合ユニークインデックスが付いていると、違う会員IDでも発生する。ここの複合ユニークインデックスのカラムたちの実際の値はちょっと複雑なので、ネクストキーロックがどこまでロックを広げているのかが特定しづらく、列挙する会員IDによっては発生したりしなかったりするのかもしれません。追記分を考慮した推測は:子テーブルのFKが複合ユニークインデックス付いている場合は、違う会員同士の更新(delete/insert)でデッドロックになる可能性がある。子テーブルのFKが単にFKによるインデックスだけなのであれば、一人の会員がブラウザ二つ起動して同時に更新(delete/insert)とかすればデッドロックになる可能性がある。それも親テーブルの排他制御を先に実行していれば問題ない。更新するのが会員だけとは限らないとか、業務によっては心配する場面は幾つもあるでしょうが。【追記】ちなみに、トランザクション分離レベルを、ReadCommittedに変更すると発生しませんでした。して0件だったら更新処理しない、っていう風にできるようにしました。これでディベロッパーは何も気にせず実装できるかと。実質的にMySQL専用プロパティと言えるでしょう。queryDelete()の内部で事前selectCount()して、0件であれば更新/削除処理しない、という振る舞いをできるようにしました。MySQLでRepeatableReadで、delete/insert方式をよくやる場合は、この設定を検討すると良いでしょう。【追記】MySQLのメーリングリストでも話題になってしましたね。MySQLのロックについてhttp://d.hatena.ne.jp/sh2/20140914なるほど、インデックスのリーフに対するロックだから、発生したりしなかったりするんですね。本当に理解するには、もうちょいじっくり読む必要がありそうです。???)ただ、はっきりしたのが、ファントムリードを防ごうとしている、という点。これはすっきりしました。業務的にファントムリードを防ぎたいか?トランザクションの本をちゃんと読まないと答えは出なさそうですが、そんなに防ぎたいケースがあまり思い付かない。あったとしても、ピンポイントで別の方法でロックするなりで実現するかも。(残りチケットの取得処理とか...)少しずつ、もろもろ整理してみたいですね。DB変更を致しました。再開したディズニーシーにはてなブログをはじめよう!jfluteさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。