1. 程式人生 > >hibernate c3p0 連線無法釋放 阻塞資料庫操作

hibernate c3p0 連線無法釋放 阻塞資料庫操作

最近寫的一個專案,發現每次啟動tomcat進行幾個資料庫操作後就會卡住,重啟tomcat又可以繼續用,幾個資料庫操作後繼續不可用。

在mysql中查詢show processlist,發現這個專案的資料庫有很多process在Sleep狀態。

關閉tomcat,重啟mysql,讓資料庫中的程序恢復0。

啟動tomcat,這時候看到這個專案的資料庫有5個連線,這是因為hibernate.cfg.xml裡面配置了最小連線數是5

<property name="hibernate.c3p0.min_size">5</property> 

用瀏覽器進行資料庫操作,每進行一次資料庫操作就會用一個新的mysql process。當進行到第6個操作的時候,沒有重用前面已經存在的5個程序,而是新建了3個。當資料庫操作超過20次的時候,這是就卡住了,因為hibernate.cfg.xml裡面配置了最大連線數是20

<property name="hibernate.c3p0.max_size">20</property> 

不知道為什麼每次都會用新的程序,根據網上找到的一些解決辦法,設定這個引數hibernate.connection.release_mode,這個引數有4個可選的value:

default,on_close,after_transaction ,after_statement 

第一感覺就是應該用on_close, 但並沒有起到作用,不知道是不是Spring的配置有什麼問題

後來嘗試了default和after_statement,只有after_statement可以起到作用

但是這裡有個問題就是使用after_statement就破壞事務性,因為每個statement執行結束後都會釋放連線,有多個操作的事務就不能保證事務性。

後來嘗試了after_transaction,還好這個可以起到作用,至少比after_statement要好的多。我的transaction是寫在DAO級別的,因為暫時還沒有需要寫在Service層的事務,根據以前專案的經驗,transaction儘量寫在有必要的地方,一個transaction執行儘量少的操作,以免阻塞其他執行緒。

至於default和on_close,據說default是等到達到最大連線數才去釋放,沒有驗證。on_close為什麼不釋放也沒有搞清楚,程式碼中是手動呼叫了sesson.close()的。

進一步的修改:之前sessionFactory是自己用Hibernate生成的,後來改成用Spring注入,似乎這個問題就沒有了,另外sessionFactory.openSession()改成了getCurrentSession();

轉載別人的:

四種釋放連線的顆粒度,從粗到細:

  1.  採用第一種default配置,在spring中配置事務管理,由於事務顆粒度比較小,事務執行結束,也不會觸發釋放的操作,直至達到連線設定回收的最大超時時間才能回收連線,連線會遲遲不釋放,導致連線池被佔滿。
  2.   採用第二種on_close, 同樣在spring中配置事務,連線一直等到session 關閉時才會被釋放,釋放較慢,同樣會導致連線池被沾滿
  3. 採用after_transcation 的策略釋放連結,每次事務都會釋放連結。採用xml配置進行全域性事務管理的配置,則不會出現連線池沾滿的現象。但是如果採用註解,而某個持久層的 Dao類未標註Transactional註解,或者xml配置中遺漏了某個dao的事務管理配置,則該Dao操作執行結束,並不是一個事務的結束,不會釋放連結,導致連結遲遲不能被釋放,久而久之會導致連線池被佔滿。
  4. after_statement 的策略釋放連線及時。 但也有一個弊端,由於每一次執行都會釋放連線,如果一個事務需要幾個執行操作,但第一次執行時連線就被釋放,連線已歸還給連線池了,第二次執行時獲取新的連線,這樣就無法保證事務性了。