データベースからオブジェクト A を取得し、現在は切り離された状態になっているとします。オブジェクト A に対応するデータベース内の行が外部で更新されます。オブジェクト A が最新ではなくなったことをアプリケーションに通知し、おそらく自動更新を行う方法はありますか? Hibernateのイベントを作成できるデータベースのトリガーでしょうか?
2 に答える
Hibernate はこのシナリオをサポートしていません。これは、サーバー上で実行され、データベースへの排他的アクセスを持つ、hibernate のインスタンスが 1 つだけ存在するクライアント サーバー アプリケーションで使用されることを意図しているためです。
Hibernate はサーバー アプリケーションに永続性を提供することになっており、クライアントはデータベースに直接ではなく、そのサーバー アプリケーションと対話することになっているため、すべての更新はサーバー アプリケーションによって開始され、Hibernate の単一のインスタンスを介してデータベースに送信されます。であるため、外部からの更新はなく、休止状態の唯一のインスタンスがすべてを完全に制御します。
もちろん、データベースをサーバーとして使用するのは魅力的です。独自のクライアント サーバー ソフトウェアを開発する必要がなくなるからです。このシナリオでは、すべてのクライアントが休止状態の独自のインスタンスを実行し、これらのインスタンスのそれぞれがデータベースと直接通信します。次に、問題は、休止状態の各インスタンスが他のインスタンスによってデータベースに加えられた変更を確認できるように何らかの方法で説得する必要があることです。これは困難な作業のように思えるかもしれませんが、節約できる点は非常に大きいため (独自のクライアント/サーバー ソフトウェアを作成し、その間に独自の通信プロトコルを使用する必要はありません)、試してみる価値があるのではないでしょうか?
さて、私はこの方法でアプリケーションを実装しましたが、後悔するようになりました。それは扱いにくく、バグが多く、パフォーマンスが非常に悪いです。
しかし、本当に試してみたい場合は、次の方法があります。
各クライアントは、行を「change_log」テーブルに追加することによって、行った各変更を記録する必要があります。また、変更ログ テーブルに表示される新しいレコードを探して、他のクライアントによって行われた変更を検出する必要があります。
変更を記録するには、Hibernate インターセプターを使用して、ローカル クライアントによってデータベースに加えられた変更を検出し、各変更を変更ログ テーブルに記録します。変更ログの各行には、自動インクリメント ID、変更されたエンティティのクラスの名前、エンティティの ID (データベース キー)、およびイベントのタイプ (追加、変更、または削除) が必要です。(もちろん、インターセプターがサポートする 4 番目のタイプのイベントである行のロードは気にしません。) これには、古き良き JDBC を使用する必要があることに注意してください。
変更を検出するには、変更について変更ログ テーブルをポーリングする別のスレッドを実行します。必要なのは、最後に確認した変更ログ行の ID を記憶し、それよりも大きい ID を持つ行があるかどうかをデータベースに問い合わせ続けることだけです。(これにはクライアント発行のタイムスタンプを使用しないでください。クライアントのクロックの必然的な小さな違いが大混乱を引き起こすためです。データベース発行のタイムスタンプは機能する可能性がありますが、データベースによって自動インクリメントされる整数 ID を使用する方が簡単です。)もちろん、ここでも JDBC を使用する必要があります。なぜなら、hibernate は変更ログに行が追加されたことを決して通知しないからです。他の誰かが行を追加した可能性があります。
変更検出スレッドはイベントを生成し、休止状態が存在するメイン スレッドに何らかの方法で渡す必要があります。これは、メイン スレッドで何らかのイベント ループが実行されているか、何らかのティック メカニズムが定期的に呼び出されている必要があることを意味します。メインスレッドが変更検出イベントを受け取ると、イベントのタイプに基づいてアクションを実行します: エンティティが追加されると、hibernate にそれをロードするように指示し、レコードが削除されると hibernate にそれを忘れるように指示します。更新され、休止状態に更新するように指示します。
個人的には、休止状態に単一のエンティティを更新するよう説得することができなかったので、変更が検出されるたびに休止状態を完全にフラッシュしていたため、パフォーマンスが非常に低下していました。来月中にこれを修正する予定ですが、修正する方法は休止状態を取り除くことになるのではないかと心配しています。
Hibernate には、これに関して大きな助けになるものはないと思います。イベントの送信先がわかるように、すべてのインスタンスとその場所を追跡する必要があります。Hibernate Interceptor または Listenerを使用して、特定のエンティティがいつ更新されたかを調べることができます。
競合する更新を処理する一般的な方法は、バージョン チェックに基づく楽観的ロックを使用することであり、Hibernate リファレンス ガイドの「楽観的同時実行制御」で詳しく説明されています。