Open Session In View
Posted on 2007-09-09 18:15 semovy 閱讀(789) 評(píng)論(0) 編輯 收藏 所屬分類: Hibernate 、spring它有兩種配置方式OpenSessionInViewInterceptor和OpenSessionInViewFilter(具體參看SpringSide),功能相同,只是一個(gè)在web.xml配置,另一個(gè)在application.xml配置而已。
Open Session In View在request把session綁定到當(dāng)前thread期間一直保持hibernate session在open狀態(tài),使session在request的整個(gè)期間都可以使用,如在View層里PO也可以lazy loading數(shù)據(jù),如 ${ company.employees }。當(dāng)View 層邏輯完成后,才會(huì)通過Filter的doFilter方法或Interceptor的postHandle方法自動(dòng)關(guān)閉session。
OpenSessionInViewInterceptor配置

















OpenSessionInViewFilter配置


















很多人在使用OpenSessionInView過程中提及一個(gè)錯(cuò)誤:

看看OpenSessionInViewFilter里的opensession方法





可以看到OpenSessionInViewFilter在getSession的時(shí)候,會(huì)把獲取回來的session的flush mode 設(shè)為FlushMode.NEVER。然后把該sessionFactory綁定到TransactionSynchronizationManager,使request的整個(gè)過程都使用同一個(gè)session,在請(qǐng)求過后再接除該sessionFactory的綁定,最后closeSessionIfNecessary根據(jù)該session是否已和transaction綁定來決定是否關(guān)閉session。在這個(gè)過程中,若HibernateTemplate 發(fā)現(xiàn)自當(dāng)前session有不是readOnly的transaction,就會(huì)獲取到FlushMode.AUTO Session,使方法擁有寫權(quán)限。
也即是,如果有不是readOnly的transaction就可以由Flush.NEVER轉(zhuǎn)為Flush.AUTO,擁有insert,update,delete操作權(quán)限,如果沒有transaction,并且沒有另外人為地設(shè)flush model的話,則doFilter的整個(gè)過程都是Flush.NEVER。所以受transaction保護(hù)的方法有寫權(quán)限,沒受保護(hù)的則沒有。
采用spring的事務(wù)聲明,使方法受transaction控制





















對(duì)于上例,則以save,add,update,remove開頭的方法擁有可寫的事務(wù),如果當(dāng)前有某個(gè)方法,如命名為importExcel(),則因沒有transaction而沒有寫權(quán)限,這時(shí)若方法內(nèi)有insert,update,delete操作的話,則需要手動(dòng)設(shè)置flush model為Flush.AUTO,如



盡管Open Session In View看起來還不錯(cuò),其實(shí)副作用不少。看回上面OpenSessionInViewFilter的doFilterInternal方法代碼,這個(gè)方法實(shí)際上是被父類的doFilter調(diào)用的,因此,我們可以大約了解的OpenSessionInViewFilter調(diào)用流程: request(請(qǐng)求)->open session并開始transaction->controller->View(Jsp)->結(jié)束transaction并close session.
一切看起來很正確,尤其是在本地開發(fā)測(cè)試的時(shí)候沒出現(xiàn)問題,但試想下如果流程中的某一步被阻塞的話,那在這期間connection就一直被占用而不釋放。最有可能被阻塞的就是在寫Jsp這步,一方面可能是頁面內(nèi)容大,response.write的時(shí)間長(zhǎng),另一方面可能是網(wǎng)速慢,服務(wù)器與用戶間傳輸時(shí)間久。當(dāng)大量這樣的情況出現(xiàn)時(shí),就有連接池連接不足,造成頁面假死現(xiàn)象。
Open Session In View是個(gè)雙刃劍,放在公網(wǎng)上內(nèi)容多流量大的網(wǎng)站請(qǐng)慎用。
hibernate open session in view 拋出異常解決方法
在使用open-session-in-view的時(shí)候,如果使用不當(dāng),有可能拋出兩種異常
1,NonUniqueObjectException
2,在配合spring使用的時(shí)候會(huì)可能會(huì)拋出org.springframework.dao.InvalidDataAccessApiUsageException
先說1,這個(gè)異常的拋出原因和解決辦法見這里:
javaeye上有了很好的事例:http://www.javaeye.com/topic/11581
解決辦法可以用merge,也可以別的辦法。
出現(xiàn)的原因,可以參考一下我前邊的文章中將merge和update的區(qū)別的內(nèi)容。
http://www.aygfsteel.com/dreamstone/archive/2007/07/29/133071.html
2的解決辦法:在這里
springside的一篇文章做了詳細(xì)說明
http://calvin.blog.javascud.org/post/46.htm
好了,現(xiàn)在問題解決了,但關(guān)于open-session-in-view的使用還有一些探討,是否應(yīng)該使用,使用的好處與壞處。
見這兩篇jdon上的文章:
http://www.jdon.com/jivejdon/thread/22374.html
http://www.jdon.com/jivejdon/thread/28955.html