快速版
基本上,我正在更新一个Hibernate表,后续查询正在加载一个陈旧的值。
详细版本
Hibernate(3.3.1.GA)和EhCache(2.4.2)。
持有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:
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" />
更新:删除数据存储区对象上的@Cache
注释会消除此问题。当然,我想缓存这些对象,因为页面修改比访问频繁得多。
那么,想法?还有其他一些相关问题,包括删除页面。所有内容都按预期更新数据库,但实际行为很不稳定。
提前致谢!
UPDATE#2 :通过调试,我可以确认数据存储区有正确的信息,当查询运行时,它会回退到二级缓存 - 它有脏信息。我认为每次数据发生变化都不能从缓存中逐出来?
答案 0 :(得分:0)
CwmService.get().flushChanges(); // commits the transaction
执行显式提交后。
flush()
仅刷新对db的更改,但不提交它。我不确定flushChanges()
。
答案 1 :(得分:0)
我发现了这个问题,但它引入了其他的东西。
基本上,在修改Book
对象的List<PageContent>
字段时,Hibernate会做三件事:
Book
和PageContent
pageNum
对象上的PageContent
字段Book
对象。这可确保后续查询将搜索新对象等。但是:
PageContent
对象因此,对页面列表的任何查询都将正常运行,但随后将回落到实际数据的陈旧二级缓存值。
我认为这是因为Hibernate认为pageNum
更改不是数据的变化,而是幕后管理的变化。但是,这是我想要阅读和显示的数据。
解决方案是在插入/删除后手动刷新每个页面。