私の休みのあるクエリが古いデータを返すのはなぜですか?
-
16-11-2019 - |
質問
クイックバージョン
基本的には、Hibernateテーブルを更新していて、後続のクエリは古い値をロードしています。
詳細バージョン
Hibernate(3.3.1.ga)とEhcache(2.4.2)。
PagesのBook
を持つList<PageContent>
オブジェクトを永続化し、この本の途中にページを追加しています。私はDatabinder / Wicketを使用していますが、それは関連しているとは思わない。
.
public void createPageContent(Book book, int index) {
Databinder.getHibernateSession().lock(book, LockMode.UPGRADE);
PageContent page = new PageContent(book);
book.addPage(page, index);
CwmService.get().flushChanges(); // commits the transaction
}
Book
の該当するフィールド/メソッドは次のとおりです。
.
@OneToMany
@JoinColumn(name="book_id")
@IndexColumn(name="pageNum")
@Cascade({CascadeType.ALL, CascadeType.DELETE_ORPHAN})
private List<PageContent> pages = new ArrayList<PageContent>();
public synchronized void addPage(PageContent page, int index) {
pages.add(index, page);
}
最終結果は、リストに新しいページが追加され、データベースがそれに応じて更新され、私は私のデータストアでこれを確認しました。ただし、「ページ#4」と「ページ#4」という次のクエリは、新しいページ#4の代わりに「古い」ページ#4をロードします。
.
criteria.add(Restrictions.eq("book", book));
criteria.add(Restrictions.eq("pageNum", pageNum));
criteria.setCacheable(true);
だから、基準からキャッシングを粗く取り除きます。データストアに問い合わせますが、は依然として間違った値を返します。ただし、両方の場合では、約2分待機しても、すべてが期待どおりに機能しています。私はキャッシングがまだ関わっていると思います。 PageContent
とBook
の両方でこのキャッシング戦略を使用してください:
.
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
私はキャッシングすることができ、初めてこのファイルを設定するだけです。これが私のehcache.xmlです:
.
<defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" statistics="false"/>
<!-- Hibernate's Cache for keeping 'lastUpdated' data on each table. Should never expire. -->
<cache name="org.hibernate.cache.UpdateTimestampsCache" eternal="true" />
<!-- Hibernate's Query Cache - should probably be limited -->
<cache name="org.hibernate.cache.StandardQueryCache" maxElementsInMemory="1000" />
update :DataStoreオブジェクトの@Cache
アノテーションを削除すると、問題が解除されます。もちろん、ページ修正がアクセスよりはるかに少ないため、これらのオブジェクトをキャッシュしたいと思います。
だから考えて?ページを削除することを含む、他にも関連しています。すべてが期待どおりにデータベースを更新しますが、実際の動作は正しくありません。
事前にありがとう!
アップデート#2 :デバッグを介して、データストアに正しい情報があることを確認し、クエリが実行されると、ダーティ情報がある2レベルのキャッシュに戻ります。データが変わるたびにキャッシュから立ち退くように、私は私次第ではないと思いますか?
解決 2
I discovered the problem, but it introduces something else.
Basically, when modifying a Book
object's List<PageContent>
field, Hibernate does three things:
- Expires the TimeStamp cache entry for both
Book
andPageContent
- Does many queries to reset the
pageNum
field on eachPageContent
object - Removes the
Book
object from the Second Level Cache.
This ensures that subsequent queries will search for new objects, etc. However:
- Hibernate fails to remove each renumbered
PageContent
object from the Second Level Cache
As a result, any query for the list of pages will run properly, but then will fall back on stale Second Level Cache values for the actual data.
I presume this is because Hibernate feels a pageNum
change is not a change in data but a change in behind-the-scenes management. However, that is the data that I would like to read and display.
The solution is to manually refresh every page after the insertion/deletion has occurred.
他のヒント
After CwmService.get().flushChanges(); // commits the transaction
do an explicit commit.
flush()
only flushes the changes to db but does not commit it. I am not sure about flushChanges()
though.