主要討論2個問題:“hibernate的session與連接的關系”、“程序中應該頻繁打開、關閉session?,還是打開后數據庫操作完成再關閉”
一、hibernate的session與連接的關系;
session與connection,是多對一關系,每個session都有一個與之對應的connection,一個connection不同時刻可以供多個session使用。
有連接池的情況下(缺省就有一個自帶的)session關閉后,connection不一定關閉,hibernate缺省使用自帶的連接池(connection.pool_size值為最大連接數),因此,session.close()后,還可以查詢到應用占用的連接:
正常情況下,每個open的session都需要close掉,如果是單線程使用的話,那么查詢oracle數據庫的連接,則一直是一個connection,如果多線程使用的話,則可能是一個或多個(多線程的open如果錯開時間,則一個,多線程如果幾乎同時,則超過一個,小於或等於連接池數據),如果session只open,不close,則每次增加一個connection。
通常每次頁面請求是一個線程,模擬多線程,可以在jsp中用frameset,每個frame的src指向一個不同的session查詢。也可以加斷點,訪問多個頁面,后訪問的先從斷點執行,這樣多線程交叉執行session操作,會發現在連接池連接較少時,會增加連接進到池中。
下面是一個jsp例子,每個frame里面都訪問了數據庫:
<frameset cols="200,200,*" >
<frame src="<%=GlobalNames.getWEB_APP()%>/sysman/roleAction.do?method=findAllRoles" name="rolelist" marginwidth="0" marginheight="0" >
<frame src="<%=GlobalNames.getWEB_APP()%>/sysman/moduleList.do" name="modulelist" marginwidth="0" marginheight="0">
<frame src="<%=GlobalNames.getWEB_APP()%>/sysman/grantTree.do" name="granttree" marginwidth="0" marginheight="0">
</frameset>
下面是在open或close時,打印的信息:
Thread:Thread[http-8080-Processor21,5,main],session created:net.sf.hibernate.impl.SessionImpl@a75737
Thread:Thread[http-8080-Processor23,5,main],session created:net.sf.hibernate.impl.SessionImpl@ab835a
Thread:Thread[http-8080-Processor21,5,main]SESSION closed:net.sf.hibernate.impl.SessionImpl@a75737
Thread:Thread[http-8080-Processor21,5,main],session created:net.sf.hibernate.impl.SessionImpl@3cbb4b
Thread:Thread[http-8080-Processor21,5,main],session created:net.sf.hibernate.impl.SessionImpl@3cbb4b
Thread:Thread[http-8080-Processor22,5,main],session created:net.sf.hibernate.impl.SessionImpl@1443800
Thread:Thread[http-8080-Processor21,5,main],session created:net.sf.hibernate.impl.SessionImpl@3cbb4b
Thread:Thread[http-8080-Processor21,5,main]SESSION closed:net.sf.hibernate.impl.SessionImpl@3cbb4b
Thread:Thread[http-8080-Processor23,5,main]SESSION closed:net.sf.hibernate.impl.SessionImpl@ab835a
Thread:Thread[http-8080-Processor22,5,main]SESSION closed:net.sf.hibernate.impl.SessionImpl@1443800
Thread:Thread[http-8080-Processor21,5,main],session created:net.sf.hibernate.impl.SessionImpl@6279d
Thread:Thread[http-8080-Processor21,5,main]SESSION closed:net.sf.hibernate.impl.SessionImpl@6279d
可見是交叉進行的,如果connection.pool_size設置為1,則執行完后,oracle的數據庫連接查看為1個,如果connection.pool_size設置為10的話,oracle的數據庫連接查看為2或3個。
二、程序中應該頻繁打開、關閉session?,還是打開后數據庫操作完成再關閉;
沒有連接池的情況下,打開關閉連接很耗資源,因此不能經常打開關閉連接,有連接池的情況下,打開或關閉連接並不耗資源,上面2種方式各有利弊,
1、可以在程序必經之路,比如filter或者某個父類的方法中,統一關閉session,
比如方法中 :session.find1; session.find2;session.find3;doSomeThing();
find1、2、3中,若都不關閉session,則是使用同一個連接,直到完成后,到filter或其他設定的必經之路才統一關閉(通過線程關聯ThreadLocal) ;
對事務操作,及時提交回滾,但是session也統一到必經之路去關閉;
2、每次都open、close。
我的建議是采用方式2,即每次都open、close。
因為每次都打開、關閉並不太耗資源,且容易將數據庫操作控制在數據庫層,第1種方式,將數據庫的關閉移動到其他層去處理了,不太好,且必經之路可能會有漏網之魚,比如別人在plugIn時,使用數據庫操作,忘記關閉,就泄露了。另外當大並發時,盡量用完連接就放回去供別的線程使用,否則如上面提到的如果doSomeThing();很耗時,導致連接等待,就影響其他線程比較嚴重了,雖然已經獲得連接的線程能以最快速度處理完自己的事情。