Hibernate4實戰 之第五部分:Hibernate的事務和併發

Hibernate自己沒有事務的實現
Hibernate 直接使用 JDBC 鏈接和 JTA 資源,不添加任何附加鎖定行爲。也就是說你在Hibernate裏面使用的事務要麼是JDBC的事務,要麼是JTA的事務。
Hibernate不鎖定內存中的對象
你的應用程序會按照你的數據庫事務的隔離級別規定的那樣運做,真正對事務的實現和支持也依賴於數據庫。
 
對於併發處理,Hibernate提供了樂觀鎖和悲觀鎖來進行併發處理
Hibernate對自動樂觀併發控制提供版本管理,針對行級悲觀鎖定,Hibernate 也提供了輔助的(較小的)API,它使用了 SELECT FOR UPDATE 的 SQL 語法
Hibernate的Session是和事務聯繫在一塊兒的
能夠經過Session去獲取事務的接口,從而進行事務的控制。
 
數據庫事務應該儘量的短
這樣能下降數據庫中的鎖爭用。數據庫長事務會阻止你的應用程序擴展到高的併發負載。所以,倘若在用戶思考期間讓數據庫事務開着,直到整個工做單元完成才關閉這個事務,這毫不是一個好的設計。
這就引出一個問題:一個操做單元,也就是一個事務單元的範圍應該是多大?
一個操做一個?一個請求一個?一個應用一個?
 
反模式:session-per-operation
在單個線程中, 不要由於一次簡單的數據庫調用,就打開和關閉一次 Session!數據庫事務也是如此。也就是說應該禁止自動事務提交(auto-commit)。
 
session-per-request
最經常使用的模式是 每一個請求一個會話。 在這種模式下,來自客戶端的請求被髮送到服務器端,即 Hibernate 持久化層運行的地方,一個新的 Hibernate Session 被打開,而且執行這個操做單元中全部的數據庫操做。一旦操做完成(同時對客戶端的響應也準備就緒),session 被同步,而後關閉。會話和請求之間的關係是一對一的關係。
Hibernate 內置了對「當前 session(current session)」 的管理,用於簡化此模式。你要作的一切就是在服務器端要處理請求的時候,開啓事務,在響應發送給客戶以前結束事務,一般使用Servelt Filter來完成。
 
非託管環境下
所謂非託管,指的是:應用程序沒有託管到J2EE環境中,一般由Hibernate本身來負責管理數據庫鏈接池。應用程序開發人員必須手工設置事務聲明,換句話說,就是手工啓動,提交,或者回滾數據庫事務。
 
使用JTA
又有兩種方式,一種是在Hibernate配置裏面修改transaction的factory類,從而在程序裏面能夠直接使用Hibernate的事務API,也就是程序不用變化。
另一種方式就是直接經過JNDI去查找UserTransaction,而後直接在程序裏面使用JTA的接口來控制事務。
應用程序級別的版本檢查
簡單點說,就是由應用程序本身實現版本檢查來確保對話事務的隔離,從數據訪問的角度來講是最低效的,不推薦使用。
 
擴展週期的session和自動版本化
Hibernate 使用擴展週期的 Session 的方式,或者脫管對象實例的方式來提供自動版本檢查。單個 Session 實例和它所關聯的全部持久化對象實例都被用於整個對話,這被稱爲 sessionper-
conversation。
Hibernate 在同步的時候進行對象實例的版本檢查,若是檢測到併發修改則拋出異常。由開發人員來決定是否須要捕獲和處理這個異常(一般的抉擇是給用戶 提供一個合併更改,或者在無髒數據狀況下從新進行業務對話的機會)。
在等待用戶交互的時候, Session 斷開底層的 JDBC 鏈接。這種方式以數據庫訪問的角度來講是最高效的方式。應用程序不須要關心版本檢查或脫管對象實例的從新關聯,在每一個數據庫事務中,應用程序也不須要載入讀取對象實例。
應用程序級別的版本檢查
簡單點說,就是由應用程序本身實現版本檢查來確保對話事務的隔離,從數據訪問的角度來講是最低效的,不推薦使用。
 
擴展週期的session和自動版本化
Hibernate 使用擴展週期的 Session 的方式,或者脫管對象實例的方式來提供自動版本檢查。單個 Session 實例和它所關聯的全部持久化對象實例都被用於整個對話,這被稱爲 sessionper-conversation。
Hibernate 在同步的時候進行對象實例的版本檢查,若是檢測到併發修改則拋出異常。由開發人員來決定是否須要捕獲和處理這個異常(一般的抉擇是給用戶 提供一個合併更改,或者在無髒數據狀況下從新進行業務對話的機會)。
在等待用戶交互的時候, Session 斷開底層的 JDBC 鏈接。這種方式以數據庫訪問的角度來講是最高效的方式。應用程序不須要關心版本檢查或脫管對象實例的從新關聯,在每一個數據庫事務中,應用程序也不須要載入讀取對象實例。
一般不須要本身去管理鎖定策略
Hibernate 老是使用數據庫的鎖定機制,從不在內存中鎖定對象。於是用戶並不須要花不少精力去擔憂鎖定策略的問題。一般狀況下,只要爲 JDBC 鏈接指定一下隔離級別,而後讓數據庫去搞定一切就夠了。
然而,高級用戶有時候但願進行一個排它的悲觀鎖定,或者在一個新的事務啓動的時候,從新進行鎖定。
 
類 LockMode 定義了Hibernate 所需的不一樣的鎖定級別
1:當更新或者插入一行記錄的時候,鎖定級別自動設置爲LockMode.WRITE。
2:當用戶顯式的使用數據庫支持的 SQL 格式 SELECT ... FOR UPDATE 發送 SQL 的時候,鎖定級別設置爲 LockMode.UPGRADE。
3:當用戶顯式的使用 Oracle 數據庫的 SQL 語句 SELECT ... FOR UPDATE NOWAIT 的時候,鎖定級別設置 LockMode.UPGRADE_NOWAIT。
4:當 Hibernate 在「可重複讀」或者是「序列化」數據庫隔離級別下讀取數據的時候,鎖定模式自動設置爲 LockMode.READ。這種模式也能夠經過用戶顯式指定進行設置。
5:LockMode.NONE 表明無需鎖定。在 Transaction 結束時, 全部的對象都切換到該模式上來。與session 相關聯的對象經過調用 update() 或者 saveOrUpdate() 脫離該模式。
 
顯示的指定鎖定模式
1:調用 Session.load() 的時候指定鎖定模式(LockMode)。
2:調用 Session.lock()。
3:調用 Query.setLockMode()。
顯示指定鎖定模式的說明
1:若是在 UPGRADE 或者 UPGRADE_NOWAIT 鎖定模式下調用 Session.load(),而且要讀取的對象還沒有被session 載入過,那麼對象經過 SELECT ... FOR UPDATE 這樣的 SQL 語句被載入。若是爲一個對象調用 load() 方法時,該對象已經在另外一個較少限制的鎖定模式下被載入了,那麼 Hibernate 就對該對象調用 lock() 方法。
2:若是指定的鎖定模式是 READ,UPGRADE 或 UPGRADE_NOWAIT,那麼 Session.lock() 就執行版本號檢查。(在 UPGRADE 或者 UPGRADE_NOWAIT 鎖定模式下,執行 SELECT ... FOR UPDATE這樣的SQL語句。)
3:若是數據庫不支持用戶設置的鎖定模式,Hibernate 將使用適當的替代模式(而不是扔出異常)。這一點能夠確保應用程序的可移植性。
 
 原創內容 轉自請註明【 http://sishuok.com/forum/blogPost/list/2481.html#7178
 視頻配套PPT,視頻地址【  Hibernate4實戰-獨家視頻課程 】
相關文章
相關標籤/搜索