简体   繁体   English

为什么我的Hibernate Query会返回陈旧数据?

[英]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: PageContentBook使用此缓存策略:

@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会做三件事:

  1. Expires the TimeStamp cache entry for both Book and PageContent 使BookPageContent的TimeStamp缓存条目PageContent
  2. Does many queries to reset the pageNum field on each PageContent object 是否有许多查询要重置每个PageContent对象上的pageNum字段
  3. Removes the Book object from the Second Level Cache. 从二级缓存中删除Book对象。

This ensures that subsequent queries will search for new objects, etc. However: 这可确保后续查询将搜索新对象等。但是:

  1. Hibernate fails to remove each renumbered PageContent object from the Second Level Cache Hibernate无法从二级缓存中删除每个重新编号的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM