2011-05-19 101 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

相關問題