記錄我在使用spring,hibernate的時候遇到的session,和事務管理的問題. spring用一個OpenSessionInView的filter來處理session was closed的問題.這個大家并不陌生. 我們項目當中的dao層有一個baseDao. 封裝了一系列對持久化對象的操作方法.C,R,U,D 條件查詢.分頁查詢.等等.而且baseDao當中的所有的find方法都是readOnly的,get和load直接調用的hibernateTemplate的get和load.當然service層當中的事務管理也是使用spring的那個事務模板.
以上配置都OK. 我遇到的問題有幾個, 如下: 問題1,需要實現這樣一個業務邏輯: 先把對象find出來.然后改變某個屬性.然后在update. 在service當中就會寫這樣一個方法.changeOrder.在changeOrder當中先用dao的find.然后在用dao的update.理論上是可行的.因為service的事務都是被spring的事務模板托管.而且changeOrder得到的connection是可寫的.(因為spring的事務模板根據對方法名的匹配來判斷獲得得connection類型).但是由于baseDao.當中的所有find方法都是 setReadyOnly(true). 這樣.當在service執行任何find的時候.baseDao將強行把connection改為只讀的.接下來在一個事務當中.任何update 和save動作都不能完成了.但是直接執行hibernateTemplate的get和load卻不會出現這個問題.因為這個connection的屬性是由spring的openSessionInView來處理的.在request一過來的時候spring會綁定一個session.到request.直至request結束.(在這段過程當中如果不認為改變connection的readOnly的屬性.這個connection將會從請求一開始到結束都是可以寫入的.) 解決的辦法就是在自己的dao當中將find方法重載.將readOnly改為false. 問題2, 有兩個方法.一個是get對象.一個是find對象.同樣也是直接調用baseDao的get和find方法. 當我對一個對象進行編輯操作的時候發現service當中的update是有效的. 但是我find出來的對象.在利用service當中的update來更新卻發現沒有任何異常.但是就是更新不了對象. 后來才明白.get方法當中是沒有對connection進行任何readOnly相關的操作.但是baseDao當中卻設置了只讀..這個時候又有一些疑問了. action并沒有進行事務管理.當先調用service的find方法(也就是調用了baseDao中的find方法).這一個事務已經提交了.然后在繼續調用service的update.為什么會更新不了對象? 原因就是在于OpenSessionInView.綁定的一個session對象在這一次的request當中.所以.從一次request.開始到結束.這個request僅僅會操作當前的一個session對象. 盡管在action當中連續調用的兩次service方法都有兩個不同的事務范圍.在一整個請求當中還是只存在一個session對象. 所以第一個service的find方法執行完畢之后已經將當前request范圍內的session改成了readOnly.以后的所有的service操作都是只讀的.后面的service一些save或者update方法都會失效.....這就是OpenSessionInView和事務之間的微妙關系. 問題3,在ajax異步調用當中.經常也會出現這一系列的問題.其實原理大都是一樣.因為ajax后來也是一個以.dwr結尾的請求.在OpenSessionInView當中加入一個filtermapping 為 .dwr 這樣它會攔截所有的.dwr請求.在所有的ajax操作當中會綁定一個session對象. 總結一下: OpenSessionInView是一個filter.它會為每一個request綁定一個session.任何接下來在這一次請求當中所有的hibernate操作.都是基于當前請求的這個session的.任何service或者dao把當前的session對象改為了readOnly后.接下來所有save or update操作將進行不了.盡管他們不是在一個service方法(不是在同一個事務當中進行). BTW.service在很大程度上是可以和dao層混合到一起.這樣可以節約很多代碼.但是.也會帶來維護的時候非常的負責.并且麻煩.特別是readOnly 和session was closed問題.會另你非常的沮喪. dao實際上是不需要用transaction來管理的.真正需要事務的是項目當中的service層.理解才是最重要的.用好OpenSessionInView會給項目帶來極大的方便. |
|