この日記は私的なものであり所属会社の見解とは無関係です。 GitHub: takahashikzn

EclipseLink固有APIを使って、DELETE文を優先させる

ひとつ前のエントリでも説明したのですが、JPAのデフォルトではDMLの実行はコミット時に行われます。


それはJPA仕様ということで理解できるのですが、
タチの悪いことに、DML文の実行順序はEntityManagerの更新系メソッドの呼び出し順序と一致しないことがあります。


どうやらJPAの仕様によると、DMLの実行順序を最適化することが許されているようです。
しかしこの最適化がダメダメなようで、そもそも「特定の順番でSQLを実行しないとエラーになる!(ex. UPDATE→DELETE)」というケースでも問答無用で順序を変えやがります。
で、まんまと一意性制約違反に引っ掛かったりして落ちる、という具合です。



調べた結果、JPAの標準APIではDMLの実行順序を制御する手段はないようです。
唯一可能なのが、処理の区切りごとにEntityManager#flushを呼び出して強制的にSQLを実行させる方法。
しかし開発者がいちいちflushするタイミングを意識してコーディングするということは、
ある意味トランザクション制御のコードを開発者に書かせることに近いものがあると思います。
これだとバグの温床になりかねません。


一応、EclipseLink固有APIを使用することで、DELETE文だけですが順序を優先させることが可能です。
次のようにすればよいです。

final JpaEntityManager jpaEntityManager =
    (JpaEntityManager) entityManager.getDelegate();

final UnitOfWork unitOfWork = jpaEntityManager.getUnitOfWork();

// DELETE文を最初に実行させる設定
unitOfWork.setShouldPerformDeletesFirst(true);