複数のユーザーがJSFとJPAを使用して医師の予約を予約する医療チャネリングセンターのアプリケーションを開発しています。シーケンス番号は、Doctor、Date、およびSessionに固有です。以前の予約を数えて一意のシーケンス番号を取得して1つ追加しようとしましたが、2つのリクエストが同時に来ると、2つの予約が同じ番号になり、機能に問題が発生します。この場合、どうすれば一意の番号を取得できますか?アプリケーション全体のBeanを使用して生成できますか?(複数の医師、セッションがあり、毎日異なる予約番号を持っている必要があるため、データベースのシーケンス番号から一意の番号を取得することは実用的ではないと思いました。)
2 に答える
これが私がそれをする方法です:
データベースに6列のテーブルがあります。
- id(自動生成された主キー)
- doctorId
- 日にち
- セッション
- カウンター
- バージョン(
@Version
楽観的ロックのために、で注釈が付けられたフィールドにマップされます)
[doctorId、date、session]に一意の制約を追加してください。
独自のトランザクション(REQUIRES_NEW伝播)で実行されるサービスを作成します。
getNextValue(doctorId, date, session)
このサービスは、データベーステーブルから3つの引数に対応するカウンターを取得し、それを返し、インクリメントする必要があります。行がまだない場合は、作成する必要があります。
2つの同時トランザクションが同じ行を同時に作成またはインクリメントしようとする可能性はまだあります。作成の場合、トランザクションの1つは、固有の制約のためにロールバックします。増分の場合、JPAの楽観的ロックにより、トランザクションの1つがロールバックします。
サービスがロールバックした場合は、例外がなくなるまで再試行します。
これにより、これらすべてのカウンターがメモリに保存されるのを防ぎ、ステートレスであるため、アプリケーションを再起動しても問題は発生せず、サーバーのクラスターがある場合でも機能します。
これは、データベースでシーケンスを使用するのに最適なケースです。
DBテーブルにIDを作成し、フィールドがシーケンスによって自動生成されることを確認する必要があります。そうすれば、2つの行に同じ値が使用されることを気にする必要はありません。