1、最近做了一個項目,掃描讀取了第三方數據庫的數據,結果本來在公司測試沒有問題的程序在客戶那邊一直報如下錯誤:
java.sql.SQLException: 關閉的連接: next
代碼如下:
- //第三方His數據庫連接
- Connection connOrc = null;
- pst_zfy = connOrc.prepareStatement(sql);
- pst_drxf.setTimestamp(1, start);
- pst_drxf.setTimestamp(2, end);
- rs_drxf = pst_drxf.executeQuery();
- while(rs_drxf.next()){
- zyh = rs_drxf.getString(1);
- drxf = rs_drxf.getDouble(2);
- }
- }catch(Exception e){
- e.printStackTrace();
- }finally{
- DBConnector.close(rs_drxf, pst_drxf, connOrc);//該close()方法如下:
- }
- /**
- * 關閉數據庫連接,釋放數據庫連接
- *
- * @param rs
- * @param pstmt
- * @param con
- */
- public static void close(ResultSet rs, PreparedStatement pstmt, Connection con) {
- if(null != rs) {
- try {
- rs.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- if (null != pstmt) {
- try {
- pstmt.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- if (null != con) {
- try {
- con.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- }
一般來說,造成該錯誤的原因只有一個就是在調用ResultSet的next()方法時對應的Connection、PreparedStatement或者ResultSet已經關閉(調用了其close()方法)。通常來說關閉PreparedStatement和ResultSet對象,肯定是我們寫的程序自己主動關閉了,至於這個錯誤,我們可以檢查自己寫的程序代碼;第二個就是關閉Connection,對於這個對象的關閉,原因比較多:可能是我們自己關閉、物理網絡原因造成數據庫連接斷開或者外部程序統一控制數據庫連接出現問題等等。
分析原因:
①、提前主動關閉Connection、PreparedStatement或者ResultSet,應該不是該原因,這個錯誤一般大家都不會犯,即使犯了,在第一次調試后第一時間就會找出來,jdbc查詢數據庫數據標准流程都是:創建連接-->>執行查詢-->>遍歷數據-->>關閉連接、釋放資源。遵循該流程應該都不會出現該低級錯誤。既然不是該錯誤,那應該與我們寫的程序關系不到,應該是什么其他原因造成了數據庫連接關閉,現在來找關閉Connection的其他原因。
②、檢查是否是其他物理原因造成的數據庫連接Connectiion關閉了,通過日志記錄,打印Connection連接對象,發現數據庫連接仍然能正常創建成功。說道這里,根據上面的程序,不知作為看客的您們是否發現問題所在了?
③、剛才說了,能關閉數據庫連接Connection的還有統一管理數據庫連接的外部插件-------數據庫連接池!!這里我就用了proxool數據庫連接池,我的配置如下:
- <proxool>
- <alias>orc</alias>
- <driver-url>
- jdbc:oracle:thin:@127.0.0.1:1521:his_db
- </driver-url>
- <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
- <driver-properties>
- <property name="user" value="sa" />
- <property name="password" value="123456" />
- </driver-properties>
- <minimum-connection-count>1</minimum-connection-count>
- <maximum-connection-count>20</maximum-connection-count>
- <house-keeping-sleep-time>30</house-keeping-sleep-time>
- <house-keeping-test-sql>select 0</house-keeping-test-sql>
- <trace>false</trace>
- <statistics-log-level>ERROR</statistics-log-level>
- </proxool>
proxool是當前非常優秀的數據庫連接池工具,相信許多java開發者應該都用過它,通常配置該連接池時,許多選項都可以采用默認,無需配置,但是在特殊情況下還是要合理配置的。proxool里面能關閉數據庫連接的配置有兩個分別如下:
- <!-- 一個活動連接的最長時間,默認5分鍾,單位毫秒 -->
- <maximum-active-time>300000</maximum-active-time>
- <!-- 一個連接的最長活動時間,默認4小時,單位毫秒 -->
- <maximum-connection-lifetime>14400000</maximum-connection-lifetime>
最長活動時間為4小時,應該不成問題,那么活動連接最長時間默認5分鍾,出問題的可能性就非常大了,這個5分鍾要求我們在創建數據庫連接到查詢完數據並關閉必須在5分鍾之內完成,否則自動關閉數據庫連接。經過仔細分析所查詢數據庫的數據,發現數據庫對應表中的數據高達上億,從這么龐大的數據中搜索查詢一次數據至少需要4至5分鍾,然后再遍歷ResultSet進行處理,結果所耗時間遠遠超過了5分鍾,所以出現上面的java.sql.SQLException: 關閉的連接: next這個錯誤也就理所當然了。
現將該配置改為15分鍾(可根據自己項目的需要進行配置,建議大家都改下,5分鍾一般來說都不夠,除非你的項目非常小,數據量非常少而且查詢數據后的處理業務邏輯非常簡單)。更改后的配置如下。
- <proxool>
- <alias>orc</alias>
- <driver-url>
- jdbc:oracle:thin:@192.168.1.12:1521:bsrun
- </driver-url>
- <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>
- <driver-properties>
- <property name="user" value="bsquery" />
- <property name="password" value="admin" />
- </driver-properties>
- <minimum-connection-count>1</minimum-connection-count>
- <maximum-connection-count>20</maximum-connection-count>
- <house-keeping-sleep-time>30</house-keeping-sleep-time>
- <house-keeping-test-sql>select 0</house-keeping-test-sql>
- <span style="color: #ff0000;"><maximum-active-time>900000</maximum-active-time></span>
- <trace>false</trace>
- <statistics-log-level>ERROR</statistics-log-level>
- </proxool>
有關proxool的配置,及其各種屬性的作用、默認值參見我另一篇文章:proxool配置詳解。