簡體   English   中英

休眠事務問題

[英]Hibernate transaction problem

我們使用帶有OpenSessionInView過濾器的Hibernate Spring MVC。 這是我們遇到的一個問題(偽代碼)

transaction 1 
load object foo
transaction 1 end

update foo's properties (not calling session.save or session.update but only foo's setters)

validate foo (using hibernate validator)
if validation fails ?
 go back to edit screen
 transaction 2 (read only)
 load form backing objects from db
 transaction 2 end
 go to view
else 
transaction 3 
session.update(foo)
transaction 3 end

我們的問題是,如果驗證失敗,則在休眠會話中foo被標記為“臟”(因為我們使用OpenSessionInView,因此在整個http請求中只有一個會話),當我們加載表單支持對象時(例如一些使用HQL查詢),在執行查詢之前進入休眠狀態,以檢查會話中是否有臟對象,當事務2提交后,更新會被寫入數據庫,它會看到foo是並刷新它。 問題在於,即使這是一個只讀事務,並且即使在事務2中沒有更新foo,hibernate也無法知道哪個對象在哪個事務中進行了更新,並且不會僅刷新該事務中的對象。 有什么建議么? 有人遇到過類似的問題嗎

更新:這篇文章進一步闡明了這個問題: http : //brian.pontarelli.com/2007/04/03/hibernate-pitfalls-part-2/

這里有一個設計問題。 您認為ORM是數據存儲的透明抽象,還是您認為它是一組數據處理庫? 我想說的是,Hibernate是前者。 存在它的全部原因是消除內存中對象狀態和數據庫狀態之間的區別。 它確實提供了低級的機制,使您可以將兩者分開撬開並分別處理,但是這樣做會降低Hibernate的許多價值。

非常簡單-Hibernate =您的數據庫。 如果您不希望某些東西持久存在,請不要更改持久對象。

在更新域對象之前,請先驗證數據。 一定要驗證域對象,但這是最后一道防線。 如果在持久對象上確實收到驗證錯誤,請不要吞下該異常。 除非您阻止它,否則Hibernate會做正確的事,那就是在那兒關閉會話。

您可以對foo運行get使其進入休眠會話,然后將其替換為在其他地方創建的對象。 但是,要使其正常工作,您必須知道對象的所有ID,以便ID對Hibernate而言是正確的。

這里有兩個選擇。 首先,由於會話是打開的,因此您實際上不需要事務2,您可以從數據庫中加載后備對象,從而避免對會話進行臟檢查。 另一個選擇是在檢索到會話后將其從會話中驅逐foo,然后在存儲更改時使用session.merge()重新附加它。

使用休眠模式時,重要的是要了解幕后到底發生了什么。 在每個提交邊界處,它將嘗試刷新當前會話中對對象的所有更改,而不管是在當前事務中進行的更改還是與此相關的任何事務。 這樣,您實際上不需要為會話中已有的任何對象調用session.update()。

希望這可以幫助

實現服務層,查看spring的@Transactional批注,並在適用時將您的方法標記為@Transactional(readOnly = true)。

您的刷新模式可能設置為自動,這意味着您實際上無法控制何時進行數據庫提交。

您還可以將刷新模式設置為手動,並且您的服務/存儲庫僅在您告訴數據庫與應用程序同步時才嘗試將它們同步。

使用Session.clear()和/或Session.evict()怎么辦?

在過濾器上設置singleSession = false怎么辦? 這可能會將您的操作置於單獨的會話中,因此您不必處理第一級緩存問題。 否則,您可能希望按照上述用戶的建議手動分離/附加對象。 如果您不希望自動刷新內容,也可以在Session上更改FlushMode(FlushMode.MANUAL)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM