私は Java/Spring/Hibernate を初めて使用し、数年間の .Net プログラミングの後、Java に本当に恋をしました。
現在、Spring (MVC、宣言型トランザクション) と Hibernate (3.6、キャッシュ プロバイダーとして - ehCache 2.5) を使用して Web アプリに取り組んでいます。Hibernate の 2 番目のキャッシュとクエリ キャッシュを使用してキャッシュしたい読み取り専用および読み書き可能なエンティティがいくつかあります。
読み取り専用エンティティにキャッシュを使用した場合、すべて問題ありませんでした。読み書きエンティティを追加し、jMeter を使用してパフォーマンス テストを実行しました。読み取り/書き込みエンティティの場合、反復不可能な読み取りの問題に直面しています。たとえば、エンティティ テーブルの読み取りと書き込みを行う複数の同時スレッドがあります。
スレッド 3 はルックアップ値を取得します。
16:34:45,304 DEBUG [http-bio-8080-exec-3] cache.StandardQueryCache: (StandardQueryCache.java:136) - cached query results were not up to date
16:34:45,304 DEBUG [http-bio-8080-exec-3] hibernate.SQL:(SQLStatementLogger.java:111) - select virtualdev0_.virtual_device_class_id as virtual1_45_, virtualdev0_.virtual_device_class as virtual2_45_, virtualdev0_.sitebox_id as sitebox3_45_, virtualdev0_.timestamp as timestamp45_ from virtual_device_class virtualdev0_ where virtualdev0_.sitebox_id=?
キャッシュが最新ではないことを発見し、エンティティをロードし、それらを第 2 レベルのキャッシュに追加し、マテリアライズして返します... ここから 16:34:45,826 までの継続的なプロセス
一方、スレッド 9 はエンティティの 1 つを削除し、第 2 レベルのキャッシュとタイムスタンプを更新します。
16:34:45,799 DEBUG [http-bio-8080-exec-9] hibernate.SQL:(SQLStatementLogger.java:111) - delete from virtual_device_class where virtual_device_class_id=?
16:34:45,814 DEBUG [http-bio-8080-exec-9] cache.UpdateTimestampsCache:(UpdateTimestampsCache.java:95) - Invalidating space [virtual_device_class], timestamp: 5466792287494145
スレッド 3 は引き続きハウスキーピング アクティビティを実行し、最後にクエリ結果をクエリ キャッシュに追加します (タイムスタンプは、スレッド 9 の削除アクションのタイムスタンプよりも高くなることに注意してください)。
16:34:45,826 DEBUG [http-bio-8080-exec-3] cache.StandardQueryCache:(StandardQueryCache.java:96) - caching query results in region: org.hibernate.cache.StandardQueryCache; timestamp=5466792287543296
したがって、この時点で削除された ID はクエリ キャッシュにあり、クエリ キャッシュは最新であると見なされます。
16:34:45,852 DEBUG [http-bio-8080-exec-9] cache.UpdateTimestampsCache:(UpdateTimestampsCache.java:122) - [virtual_device_class] last update timestamp: 5466792287494145, result set timestamp: 5466792287543296
したがって、ルックアップを再度取得しようとすると、クエリ キャッシュが検索され、2 番目のキャッシュからエンティティの具体化が開始されます。
16:34:45,852 DEBUG [http-bio-8080-exec-9] cache.StandardQueryCache:(StandardQueryCache.java:140) - returning cached query results
ただし、削除されたアイテムはそこにないため、db へのクエリが実行されます。
16:34:45,863 DEBUG [http-bio-8080-exec-9] loader.Loader:(Loader.java:2022) - loading entity: [com.test.models.VirtualDeviceClass#0b2f363f-fbb9-4d17-8f86-af86ebb5100c]
16:34:45,873 DEBUG [http-bio-8080-exec-9] hibernate.SQL:(SQLStatementLogger.java:111) - select virtualdev0_.virtual_device_class_id as virtual1_45_0_, virtualdev0_.virtual_device_class as virtual2_45_0_, virtualdev0_.sitebox_id as sitebox3_45_0_, virtualdev0
Load メソッドを使用しているため、エンティティが db に見つからない場合は例外がスローされます。私の場合、エンティティが更新されることはめったになく、それが起こる可能性があり、それが心配です。この問題を克服するためのアイデアはほとんどありません。
a) trx 分離レベルを DB で Repeatable Read に設定します (ただし、db からデータを読み取った後にキャッシュ ロジックへの追加が行われるため、これが役立つとは考えていません) b) エンティティの削除/更新時に手動で標準クエリ キャッシュを強制的に削除します c) 実行しますクエリ キャッシュをまったく使用しない (ほとんどの db クエリをルーティングして、2 番目のキャッシュを使用するようにしてください)
以前にこの問題に直面した人はいますか?