web-dev-qa-db-ja.com

JPA同時実行の問題「バッチのリリース時にまだJDBCステートメントが含まれていました」

最大再試行回数に達するまでエンティティを複数回保存しようとするwhileループで解決しようとした並行性の問題があります。この問題を解決する他の方法があるかどうかについては話を避けたいです。他のStackoverflowの投稿もあります。 :)長い話:派生した列には一意の制約があり、衝突を避けるために増分し続ける数値部分が含まれています。ループでは、私は:

  1. max(some_value)を選択
  2. 結果を増やす
  3. この新しい結果で新しいオブジェクトを保存しようとします
  4. 明示的にエンティティをフラッシュし、一意のインデックスが原因で失敗した場合、DataAccessExceptionをキャッチします。

ループがステップ1に戻って選択しようとする場合を除いて、これらはすべて機能しているようです。

17:20:46,111 INFO  [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl] (http-localhost/127.0.0.1:8080-3) HHH000010: On release of batch it still contained JDBC statements
17:20:46,111 INFO  [my.Class] (http-localhost/127.0.0.1:8080-3) MESSAGE="Failed to save to database. Will retry (retry count now at: 9) Exception: could not execute statement; SQL [n/a]; constraint [SCHEMA_NAME.UNIQUE_CONSTRAINT_NAME]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"

そして、新しい例外がキャッチされます。一意制約違反を引き起こし、DataAccessExceptionをスローする最初のフラッシュは、エンティティマネージャのバッチをクリアしないようです。これに対処する適切な方法は何ですか? JPAでSpringを使用していますが、エンティティマネージャーに直接アクセスできません。必要な場合は注入できると思いますが、これはこの問題の痛みを伴う解決策です。

13
Chris Williams

それを行うことはできません。何かをフラッシュして失敗すると例外がスローされると、トランザクションはロールバックとしてマークされます。つまり、例外をキャッチして続行することは問題ではなく、ロールバックが発生します。実際には、どの例外がスローされたかはまったく関係ありません。デフォルトでは、Springのトランザクションマネージャーは未チェック例外ごとにロールバックします。 @TransactionalアノテーションでnoRollbackForを明確に定義することにより、これを克服できます(アノテーションドライバートランザクションを使用している場合)

編集-トランザクションはおそらくデータベースレベルでロールバックとしてマークされるため、この制約違反の場合にも役立ちません。

11
paranoidAndroid

私はこの質問に同じエラーが出るのを見つけました。私の場合、問題はトリガーと行ロックの奇妙な組み合わせが原因でした( テーブルにトリガーが追加されたときのPSQLExceptionとロックの問題 を参照)。ただし、このエラーが原因ではなく主なエラーの結果であることを発見するには、時間がかかりました。 Hibernateがセッションをフラッシュし、何らかの制約違反が発生すると、JDBC例外を受け取り、最終ブロックでabortBatchの呼び出しを試みます。セッションにステートメントが残っている場合、Hibernateはこの警告を発しますが、実際のエラーは以前のどこかで検索する必要があります。

0