2011-05-19 72 views
4

快速版本为什么我的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分钟,一切都按预期工作。我认为缓存仍然涉及。无论PageContentBook利用这个缓存策略:

@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:删除@Cache注解数据存储区对象中删除的问题。当然,我想缓存这些对象,因为页面修改比访问要少得多。

那么,想法?还有其他几个相关问题,包括删除页面。一切都按预期更新数据库,但实际行为不可靠。

在此先感谢!

更新#2:通过调试,我可以确认数据存储具有正确的信息,并且当查询运行时,它回退到二级缓存 - 它有脏信息。每当数据发生变化时,我认为我无法从缓存中逐出?

+0

当您运行条件查询时,您是否看到正在运行的sql? (logger org.hibernate.sql) – 2011-05-19 20:34:10

+0

是的,我的日志语句都支持我上面提出的评论。当我查询缓存时,EhCache在缓存条目上报告了“命中”。当我做了'setCacheable(false)'查询确实运行。 – jbrookover 2011-05-19 21:25:18

+1

所以接下来的事情是,你确定你期望在数据库中所做的更改肯定在数据库中,并且对于另一个连接是可见的? – 2011-05-20 06:04:17

回答

0

我发现了这个问题,但它引入了其他的东西。

基本上,修改Book对象的List<PageContent>场时,休眠做了三两件事:

  1. 过期两个BookPageContent
  2. 时间戳缓存条目做了很多查询到pageNum场重置每个PageContent对象
  3. 从二级缓存中删除Book对象。

这确保后续查询将搜索新的对象,等等。然而:

  1. 休眠未能从第二级缓存

删除每个重新编号PageContent对象作为结果,查询页面列表的任何查询都会正常运行,但是会返回实际数据的陈旧二级缓存值。

我认为这是因为Hibernate感觉pageNum更改不是数据的变化,而是后台管理的变化。但是,这是我想阅读和显示的数据。

解决方法是在插入/删除发生后手动刷新每个页面。

0

CwmService.get().flushChanges(); // commits the transaction之后做一个明确的提交。 flush()只刷新对数据库的更改,但不提交它。虽然我不确定flushChanges()

+0

CwmService.get()。flushChanges()是我的自定义方法。它运行Hibernate的Transaction.commit(),根据JavaDoc的说法,“刷新相关的Session”。 – jbrookover 2011-05-19 21:20:55

+0

您是否使用单独的事务来每次写入db?事务完成后,你能看到db中的变化吗? – Bhushan 2011-05-19 21:55:10

相关问题