2012-04-17 43 views
3

我在JSF項目後面使用Hibernate。

在主頁面中,我有一個代表對象列表的數據表。

我使用Hibernate成功地更新了對象的屬性(在數據表中找到)。更新後,通過使用「xxx?faces-redirect = true」進行重定向來刷新頁面。我重定向頁面以避免「重複表單提交」類問題。

然後,如果我多次點擊F5,更新對象的舊屬性值可能會回到頁面。

據我所知,這是一個Hibernate會話問題。因爲如果我在每次使用後立即關閉,則不會發生此問題。但是,由於延遲獲取策略,我無法在事務處理後關閉會話。

簡而言之,休眠可能會帶來一個對象的舊值,儘管它已被成功更新。我怎樣才能避免這樣的問題?休眠不一致:會話返回舊值

PS:我懷疑關於Hibernate的緩存機制,並用我殘疾一級和二級緩存:

<property name="hibernate.cache.use_query_cache">false</property> 
<property name="hibernate.use_second_level_cache">false</property> 

,但它並沒有太多工作..

更新:後@Johanna的回覆,我控制了會話實例的id,並指出我的HibernateUtil類在大多數時間返回一個不同的會話或者打開一個新的會話。這裏是getSession()方法:

public static Session getSession(){ 
    Session se = HibernateUtil.session.get(); 
    if(se == null) 
    { 
     se = sessionFactory.openSession(); 
     HibernateUtil.session.set(se); 
    } 
    return se; 
} 

我假設,一旦我有一個會議,我做的一切都是上市,更新等,與該會話。因爲我在getSession()方法中進行了必要的控制。我在哪裏犯錯誤?

回答

4

use_query_cache和use_second_level_cache都不能禁用第一級緩存。一級緩存始終處於打開狀態。

如果你真的不想使用第一級緩存,那麼你必須使用StatelessSession而不是Session。但StatelessSession功能較少,您需要的某些方法可能會丟失。

如果您只想從一級緩存中刪除一些對象,則可以使用Session.evict()。

不過我想知道爲什麼Hibernate會給你帶來舊的價值。如果每個數據庫實體在會話中只有一個實例(即,您更新的對象的實例與列表中顯示的實例相同),則不應該發生這種情況。如果你使用兩個不同的實例,那麼這是正常的Hibernate提供舊值(如果你使用兩個會話實例,一個用於列表和一個用於更新,那麼你也可以在列表中獲得舊值)。所以,當你修復你的應用程序時,也許你不必驅逐這個對象。

更新後編輯: 在你的簡短的codelet中,我看不到爲什麼你作爲單個用戶使用應用程序時會出錯。

但一般情況下:您使用JSF,因此它可能是一個可供許多用戶使用的Web項目。

Hibernate Session對象不是線程保存,即。即如果不同的用戶同時使用它,它可能不會工作。每個用戶都需要自己的會話對象。因此,您可以將Hibernate會話實例存儲在Http會話實例中(甚至有時您必須使用'synchronized'方法(或對象),僅用於第一次請求的答案到達之前用戶再次按下按鈕的情況)。

第二次編輯:我覺得你有和this question一樣的問題。

可能是您從任何地方複製了您的代碼,如引用問題的DAO。我想你的HibernateUtil類,你從其他地方複製的代碼,將hibernate會話存儲在一個ThreadLocal對象中。即一個hibernate會話綁定到一個線程。

但是你正在做一個web項目。在那裏你應該綁定一個Hibernate會話給一個用戶(或瀏覽器),我。即到一個Http會話。但是你不知道在哪個線程中處理了來自一個http會話的請求。因此,在你的解決方案中,相同的Http會話可能會得到不同的Hibernate會話,或者不同的Http會話可能會得到相同的Hibernate會話。這取決於你的Http服務器。

解決方案:將休眠會話放入Http會話中(並且使用ThreadLocal對象執行而不是)。您可以使用HttpServletRequest.getSession()HttpSession.getAttribute()/HttpSession.setAttribute()獲得Http會話對象,您可以設置Hibernate會話和其他Http會話相關數據。

+0

我做了一個控制,以避免有兩個不同的會話。因此,如果有公開會議,我不會創建另一個會議,我將返回公開會議。因此,不應該存在兩個不同的會話。在列出,更新等時使用現有會話是否是一個問題 – 2012-04-18 06:27:29

+0

它應該只能使用一個會話。我建議您在調試模式下啓動應用程序,並檢查您更新的實例和獲取舊值的實例是否是同一個實例(Eclipse調試器中的地址或實例ID相同) – Johanna 2012-04-18 07:42:45

+0

我試過如你所說,我需要用我的觀察來更新這個問題。等待你的幫助,謝謝.. – 2012-04-18 10:28:20