快速版本
基本上,我正在更新hibernate表,后续查询正在加载陈旧的值。
详细版本
hibernate(3.3.1.GA)和EhCache(2.4.2)。
包含页面的持久Book对象,List<PageContent>我将页面添加到本书的中间。我正在使用Databinder / Wicket,尽管我认为这并不相关。
Book
List<PageContent>
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);
因此,我勉强从条件中删除了缓存。它查询数据存储,但 仍返回错误的value 。但是,在两种情况下,如果我等待约2分钟,一切都会按预期进行。我认为仍然涉及缓存。双方PageContent并Book使用该缓存策略:
PageContent
@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我的数据存储对象上的注释可消除问题。当然,我想缓存这些对象,因为页面修改的频率远低于访问。
@Cache
那么,有什么想法吗?还有其他一些相关问题,包括删除页面。一切都会按预期更新数据库,但是实际行为却很奇怪。
提前致谢!
更新#2 :通过调试,我可以确认数据存储区具有正确的信息,并且当查询运行时,它会退回到具有脏信息的二级缓存中。我想是不是每次数据更改时都要从缓存中逐出?
我发现了问题,但引入了其他问题。
基本上,在修改Book对象的List<PageContent>字段时,Hibernate会执行三件事:
pageNum
这样可以确保后续查询将搜索新对象等。但是:
结果,对页面列表的任何查询都将正常运行,但随后将退回到实际数据的陈旧二级缓存值。
我认为这是因为Hibernate认为pageNum更改不是数据更改,而是后台管理的更改。但是,这就是我要读取和显示的数据。
解决方案是在插入/删除发生后手动刷新每个页面。