デッドロックは非常に頻繁に発生するため、アプリケーションの一部のスレッドが長期間ロックを保持しているように見えます。
アプリケーションの各スレッドは、データベースへのアクセス中に独自のデータベース接続を使用するため、データベースの観点からは、2つのスレッドはデータベースロックを競合する2つの別個のクライアントです。
スレッドが長期間ロックを保持し、特定の順序でそれらを取得し、2番目のスレッドが同じロックを取得するが、順序が異なる場合、デッドロックが発生することになります(こちら この頻繁なデッドロックの原因の詳細については)
また、読み取り操作でデッドロックが発生しています。これは、一部のスレッドが読み取りロックも取得していることを意味します。これは、スレッドがREPEATABLE_READ
でトランザクションを実行している場合に発生します 分離レベルまたはSERIALIZABLE
。
これを解決するには、Isolation.REPEATABLE_READ
の使用法を検索してみてください およびIsolation.SERIALIZABLE
プロジェクトで、これが使用されているかどうかを確認します。
別の方法として、デフォルトのREAD_COMMITTED
を使用します 分離レベルで、エンティティに@Version
で注釈を付けます 、楽観的ロックを使用して同時実行を処理する
代わりに。
また、長時間実行されているトランザクションを特定してみてください。これは、@Transactional
の場合に発生することがあります。 は間違った場所に配置され、トランザクションを1行ずつ実行するのではなく、たとえばバッチ処理の例でファイル全体の処理をラップします。
これは、エンティティマネージャーの作成/削除とトランザクションの開始/コミット/ロールバックをログに記録するためのlog4j構成です:
<!-- spring entity manager and transactions -->
<logger name="org.springframework.orm.jpa" additivity ="false">
<level value="debug" />
<appender-ref ref="ConsoleAppender" />
</logger >
<logger name="org.springframework.transaction" additivity ="false">
<level value="debug" />
<appender-ref ref="ConsoleAppender" />
</logger >
- @Transactionalを介してテーブルをロックせずに、どういうわけか更新クエリ(JPA / Nativeのいずれか)を実行できますか?
更新クエリは、ネイティブクエリまたはJPQL を介して可能です。 。
- @Transactionalを使用せずにセッションに参加できますか? たとえば、スケジュールされたスレッドは、エンティティのLazyフィールドを読み取ろうとするとLazyInitializationExceptionになります-メソッドに@Transactionalの注釈が付いていない場合、セッションはありません
@Transactional
のないメソッドの場合 、クエリは独自のエンティティマネージャで実行され、クエリの実行直後にセッションが閉じられるため、切り離されたエンティティのみが返されます。
したがって、@Transactional
のないメソッドでの遅延初期化例外 は普通。 @Transactional(readOnly=true)
に設定できます 同様に。