私が解決しようとしている問題について説明しようと思います。私が開発したアプリには、Spring トランザクション管理の実装が不十分であることに気付きました。サービス層メソッドではなく、DAO インターフェイス メソッド (CRUD) で定義されたトランザクションで宣言型アプローチを使用しています。これは、ある種のメッセージ処理を行う Web アプリであり、複数のスレッドが同じメッセージ インスタンスに対して同時に動作します。一般的な手順は次のとおりです。
- メッセージは T1 (トランザクション 1) で作成され、送信キューに入れられます。T1 は終了します。
- メッセージは別のスレッドによってキューから取得され、送信され、送信時刻といくつかの追加情報で更新されます。メッセージオブジェクトのプロパティを設定し、dao.update(m) を呼び出すと、t2 が起動します。
- t2 がコミットする前に、配信レポートが受信され、Tread3 は同じメッセージ オブジェクトを db (ステップ 1 で保存) で見つけて処理を開始し、その状態プロパティを更新して dao.upate(m) を呼び出し、t2 がまだ進行中に t3 が開始されるようにします。
- 別のスレッド (スレッド 4) は、t4 で状態を再度変更することにより、同じメッセージ オブジェクトをさらに処理します。
時々発生する結果は、t2 からの変更が失われ、送信時刻が db で null になることです。アプリの設計を改善し、同じメッセージの同時処理を防止することでこの問題を解消する方法を見つけるのに助けが必要です。
トランザクションの再設計 (dao の代わりにサービス レベルで使用) と、シリアライズ可能な分離レベル (またはその他) の使用に集中する必要がありますか。
JPAエンティティマネージャのロックを使用する必要がありますか?
アプリは、Spring 3 と JPA2 を休止状態の実装で使用します。