在從excel導入10W條數據到mysql中時,運行一段時間就會拋這個異常,連接池問題
org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is org.hibernate.TransactionException: JDBC begin failed: Caused by: java.sql.SQLException: connection holder is null at com.alibaba.druid.pool.DruidPooledConnection.checkState(DruidPooledConnection.java:1085) at com.alibaba.druid.pool.DruidPooledConnection.getMetaData(DruidPooledConnection.java:825) at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:285)
找了下解決方案
1.
給jdbc url 增加 autoReconnect=true 一定能解決你的問題,可以定期觀察一下 show processlist
改進方法如下:
<property name="url" value="jdbc:mysql://localhost/數據庫實例名稱?&useUnicode=true&characterEncoding=utf-8&autoReconnect=true"/>
2.
尋找支持重連的連接池。
注意:c3p0連接池支持重連;重連參數是:
idleConnectionTestPeriod 設置空閑連接測試周期
preferredTestQuery : 設置一查詢語句,用於重連測試
testConnectionOnCheckin設置為true
testConnectionOnCheckout設置為true
在sessionFactory里配置:
<property name="hibernateProperties">
<props>
<prop key="hibernate.autoReconnect">true</prop>
</props>
</property>
這兩種不同的配置都是使連接池自動重連
后面發現問題還是存在
通過研究源碼我可以確定"Druid提供的getConnection()或者getConnection(long maxWaitMillis)方法不能保證在同一個線程中獲取的始終是一個連接,直到顯示的將連接關閉嗎?"。必須在程序在緩存從Druid中取出的連接才能保證現一個事務在使用的是同一個連接。
而拋出“connection holder is null”異常的原因可能在於:
關閉長時間不使用的連接超時時間,單位秒
removeAbandonedTimeout
假設這個參數的值 為30分鍾,當一個連接在獲取后30分鍾還沒釋放,也就是Connection的DruidPooledPreparedStatement對象執行完了executXXX()方法但還未執行close、commit、rollback方法,對應於Connection的running參數的值為false,這時Durid的DestroyConnectionThread線程會自動將該連接回收。當程序要commit()連接時會執行checkState()方法,這個方法會執行以下代碼:
if (holder == null) { if (disableError != null) { throw new SQLException("connection holder is null", disableError); } else { throw new SQLException("connection holder is null"); } }
這段代碼就是我們看到的“connection holder is null”異常的來源,因此,我們需要做的就是根據Druid提供的監控信息(主要看“連接持有時間分布”的值)修改這個參數的值,它的值一定要比最長的連接持有時間還要大。
最后我把鏈接自動清除配置關閉解決了問題
removeAbandoned=false
如果把這個時間調整大一點應該也是可以的
removeAbandonedTimeout=1800