[英]Why is my Hibernate Query returning stale data?
Quick Version 快速版
Basically, I'm updating a Hibernate Table and subsequent queries are loading a stale value. 基本上,我正在更新一个Hibernate表,后续查询正在加载一个陈旧的值。
Detailed Version 详细版本
Hibernate (3.3.1.GA) and EhCache (2.4.2). Hibernate(3.3.1.GA)和EhCache(2.4.2)。
Persisted Book
object with a List<PageContent>
of pages and I'm adding a page to the middle of this book. 带有
List<PageContent>
页面的持久Book
对象,我在本书的中间添加了一个页面。 I'm using Databinder/Wicket, though I do not think that is related. 我正在使用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
}
The applicable fields/method in Book
are: 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);
}
The end result is that there is a new page added to a list and the database is updated accordingly and I've confirmed this in my datastore. 最终结果是有一个新页面添加到列表中,数据库也相应更新,我已在我的数据存储区中确认了这一点。 However, the next query for a page, say "Page #4," loads the "old" Page #4 instead of the new Page #4:
但是,对于页面的下一个查询,例如“页面#4”,会加载“旧”页面#4而不是新页面#4:
criteria.add(Restrictions.eq("book", book));
criteria.add(Restrictions.eq("pageNum", pageNum));
criteria.setCacheable(true);
So, I grudgingly remove caching from the criteria. 所以,我勉强从标准中删除了缓存。 It queries the datastore, but still returns the wrong value .
它查询数据存储区,但仍返回错误的值 。 However, in both cases, if I wait about 2 minutes, everything is working as expected.
但是,在这两种情况下,如果我等待大约2分钟,一切都按预期工作。 I presume caching is still involved.
我认为缓存仍然存在。 Both
PageContent
and Book
use this caching strategy: PageContent
和Book
使用此缓存策略:
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
I confess I'm new to caching and just set up this file for the first time. 我承认我是新手,只是第一次设置这个文件。 Here's my ehcache.xml:
这是我的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 : Removing the @Cache
annotations on my datastore objects removes the problem. 更新 :删除数据存储区对象上的
@Cache
注释可以解决问题。 Of course, I would like to cache these objects because page modification is much less frequent than access. 当然,我想缓存这些对象,因为页面修改比访问频繁得多。
So, thoughts? 那么,想法? There are several other issues related as well, including with deleting pages.
还有其他一些相关问题,包括删除页面。 Everything updates the database as expected, but actual behavior is wonky.
一切都按预期更新数据库,但实际行为是不可靠的。
Thanks in advance! 提前致谢!
UPDATE #2 : Via debugging, I can confirm that the Datastore has the correct information and when the query runs, it falls back on the Second-Level Cache - which has dirty information. 更新#2 :通过调试,我可以确认数据存储区有正确的信息,当查询运行时,它会回退到二级缓存 - 它有脏信息。 I presume it's not up to me to evict from the cache every time the data changes?
我认为每次数据发生变化时都不能从缓存中逐出?
After CwmService.get().flushChanges(); // commits the transaction
在
CwmService.get().flushChanges(); // commits the transaction
之后CwmService.get().flushChanges(); // commits the transaction
CwmService.get().flushChanges(); // commits the transaction
do an explicit commit. CwmService.get().flushChanges(); // commits the transaction
做一个显式提交。 flush()
only flushes the changes to db but does not commit it. flush()
仅将更改刷新到db但不提交。 I am not sure about flushChanges()
though. 我不确定
flushChanges()
。
I discovered the problem, but it introduces something else. 我发现了这个问题,但它引入了其他的东西。
Basically, when modifying a Book
object's List<PageContent>
field, Hibernate does three things: 基本上,在修改
Book
对象的List<PageContent>
字段时,Hibernate会做三件事:
Book
and PageContent
Book
和PageContent
的TimeStamp缓存条目PageContent
pageNum
field on each PageContent
object PageContent
对象上的pageNum
字段 Book
object from the Second Level Cache. Book
对象。 This ensures that subsequent queries will search for new objects, etc. However: 这可确保后续查询将搜索新对象等。但是:
PageContent
object from the Second Level Cache PageContent
对象 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. 我认为这是因为Hibernate感觉
pageNum
更改不是数据的变化,而是幕后管理的变化。 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. 解决方案是在插入/删除发生后手动刷新每个页面。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.