原文摘自:http://forum.javaeye.com/viewtopic.php?t=17501&postdays=0&postorder=asc&start=0
![]() |
![]() ![]() |
| |
我明白robbin你的意思,我說的情況就是網絡傳輸導致的15秒。本身頁面執行的時間,比如freemarker渲染一下模板,這個速度是非常快的,沒問題,可是我的疑問就在于如果網絡傳輸狠慢,會不會影響到數據庫連接。 假設WebWork+Hibernate+FreeMarker架構模型是這樣的 Request | |---other filters... | |---OpenSessionInView Filter | |-----WebWork Controller | |---Action | |---FreeMarker Result(對response.getWriter()做process()操作) | | |---OpenSessionInView Filter | |---other filters... | Request 這里有兩種情況。 一是頁面緩沖區足夠大,足夠一次性容納所有的頁面,這樣渲染頁面就會一次性進入緩沖區,然后返回到OpenSessionInView Filter,關閉Session,數據庫連接返回池中,一切OK。 第二種情況我是重點想討論的,也是我的疑慮所在。那就是假如這個頁面比較大,超出叻頁面緩沖區的大小,那么渲染頁面時,就拿FreeMarker/Velocity這樣的模板語言來說,它執行process/merge方法,往servlet的response writer/outputStream里面寫東西,寫著寫著,發現寫不動叻,是緩沖區滿叻,而這個writer/outputStream,正是服務器同用戶之間建立的socket請求,于是底層代碼開始先向用戶傳輸一部分頁面,傳好后,又有叻新的緩沖區,FreeMarker/Velocity的方法又能向緩沖區里寫東西叻。而傳輸頁面這個過程,又耗費叻幾秒鐘的時間,就導致叻數據庫連接被占用叻狠長的時間。 可能我描述的是錯誤的,希望robbin指正!:) |
![]() |
![]() ![]() |
| |
我覺得這個問題歸根結底就是AppServer究竟會如何實現頁面輸出。那么必然和具體的應用服務器實現有關系。那么至于每個AppServer究竟會怎樣去實現,我就不得而知了。起碼大家可以研究一下Tomcat源代碼看看tomcat是如何實現的。 confluence采用的就是Hibernate/Spring/Webwork架構,OpenSessionInView,以confluence這么廣的使用,好像也沒有聽過這方面的問題投訴。 |
![]() |
![]() ![]() |
| |
我寫了一個簡單的webapp在Tomcat5.5.12上面做了一個小測試。在JSP頁面里面循環1萬次輸出字符串,程序在遠程服務器上面運行,網絡是ADSL寬帶,filter確實被阻塞了20秒左右。然后我另外開了一個flashget去下載服務器上的大文件,模擬網絡速度比較慢的環境,filter被阻塞了50秒左右。分別做了三次測試。另外當頁面下載過程中直接點擊瀏覽器stop按鈕,則JSP執行被打斷,filter立刻解除阻塞,被執行完畢。 結論證明,使用OpenSessionInView的時候,如果render的頁面數據量非常大,并且客戶端網絡速度很慢的情況下,由于頁面的輸出時間過程很長,確實會造成filter被長時間阻塞。對于OpenSessionInViewFilter來說,就會造成數據庫連接被保持很長的時間,才能被關閉。 不過,對于Spring的OpenSessionInViewFilter來說,雖然數據庫連接被保持了過長的時間,但是并沒有鎖定數據庫資源,特別是事務資源。因為Spring的事務是通過TransactionInterceptor來實現的,在MVC結構中,當最后一個業務bean被調用結束以后,Transaction就已經被提交了。此后,雖然數據庫連接還保持中,但是數據庫資源沒有鎖定問題。 完整的調用示意圖: request -> (OpenSessionInViewFilter打開Session) -> ServletDispatcher -> Action -> (打開Connection,啟動事務) -> spring bean -> another spring bean -> (提交事務) -> bean執行完畢,返回Action -> render view(JSP/Template) -> (OpenSessionInViewFilter關閉Session和Connection) |
![]() |
![]() ![]() | ||
| |||
robbin的分析很透徹,對于最后一點,我稍有疑問。
其實我認為數據庫連接被保持過長時間有時候會有很大的問題。尤其是對于采用數據連接池的情況,如果你的數據庫連接一直被保持,那么這個資源就未被釋放。假設說這個數據連接池的最大連接數為15,我感覺很容易造成數據庫的連接不夠用。 不清楚底層的實現是如何做的,或許我的疑問有些多慮。 |
![]() |
![]() ![]() | ||||
| |||||
按道理來說,數據庫連接應該盡早被釋放,以緩解數據庫資源的壓力,延遲很久才釋放,確實會導致需要更多的數據庫連接。這個就只能擴大連接池數量,增加數據庫最大允許連接數來解決了。 此外,Session被延遲很久釋放,那么Session占用的一級緩存也會占用比較長時間,這意味著會無謂消耗更多的JVM內存。 因此,OpenSessionInView雖然確實方便,但是大家還是慎用吧。對于那些頁面渲染速度很慢,撥號連接用戶數量過多的網站就最好不要使用。 |
![]() |
![]() ![]() | ||
| |||
確切的應該是大并發用戶量的情況吧。這個問題一直都存在,在1年多前我和robbin爭論中就提出來了過。hibernate2的代碼可以看到session是和connection緊密耦合的(Hibernate3沒看過)。但hibernate大部分被用于并發用戶可預見的intranet應用,所以問題也不是很大。如果并發用戶多,對connection pool資源, opensession in view在hibernate中使用會構成較大壓力。如果jboss j2ee5 server采用hibernate作為ejb3實現,沒有做修正的話,同樣的問題也會存在于jboss j2ee5 server中。 上一次由Charlesxp于2005-12-14 周三, 上午10:25修改,總共修改了2次 |
![]() |
![]() ![]() | ||
| |||
在dao中對要render的集合強制初始化。 |
![]() |
![]() ![]() | ||
| |||
Hibernate.initialize(foo.getBars); |