c3p0 - CLOSE BY CLIENT STACK TRACE

由一個DEBUG說開去

先交代一下背景。前端

昨天晚上一個羣友在羣裏問我一個問題。他當時在給Oracle 10g配置C3P0鏈接池。最起初呢,這傢伙用的是ojdbc14.jar。寫法是標準的Spring的寫法,可是就是不行。後來我說,你換個包。換成classes12.jar看看。順利執行了。java

話說,後來又出了一個問題。他問我說,執行是執行了,可是出現個新的問題。程序員

XXXX(1234567890123456) 19:02:17
新問題又出來了sql

XXXX(1234567890123456) 19:02:28數據庫

NewPooledConnection - closed by a client.
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:566)
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:234)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyRe
source(C3P0PooledConnectionPool.java:470)
at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:96
4)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.ja
va:547)
C3P0PooledConnectionPool - Successfully destroyed PooledConnection: com.mchange.v2.c3p0.impl.NewPool編程

我看到那個DEBUG,我說,是調試信息,修改一下LOG4J的等級就好了。app

這個羣友很不解的問,既然成功了,幹嗎還要丟異常出來?async

這裏就不得不說到兩個商業開發的原則問題了。ide

第一,對上家傳入數據嚴加過濾,對傳出給下家的數據仔細檢查。模塊化

第二,合理使用異常。

第一點其實很簡單的。也就是模塊化開發的一個思想問題。對本身的行爲負責。前端返回的數據到底是什麼,須要進行校驗。不合格的剔除或者是修正。合格的處理完後,在傳出以前也要加以校驗,是否合格。

具體到這個問題裏,就是來自Spring關於數據源的那個配置文件。

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">

//略去數據源相關信息的配置

</bean>

這個配置文件裏,有兩個信息是很管用的。一個是class,一個是destroy-method。簡單點說,一個是數據源的實現類,一個是析構方法。Spring在讀取這個配置文件之後,須要根據這些信息來實例化一些類,而後內部再根據中間的那些配置信息來實際構造數據源。好比username啥的。

但是來了個問題。不能保證這裏的ComboPooledDataSource數據源必定是可用的,也不能保證close方法必定能關閉鏈接,對吧?Spring自己不能檢查這個類是否真實有效,毫無Bug。實際上呢,也檢查不了。一樣的,close方法是否有效,也須要進行檢查。這就是我剛纔說的,對上家數據的嚴加檢查。

那好吧,怎麼檢查呢?最簡潔的方法莫過於實際構造一下,鏈接池,獲取數據庫鏈接,執行一個測試語句,而後關閉鏈接。若是一切都成功,那就OK。關於那個測試語句,配置過WebSphere數據源的同窗們還記得不?有個SQL語句會默認的寫在數據源配置裏,是 " SELECT 1 FROM TABLE "。嗯,對的,這個就是測試語句。

這一套流程能走得通,走的順,那麼就能夠在本身能力範圍內說這個數據源和鏈接池是能用的,對吧?

這裏補充一個知識。java.sql.Connection,這玩意不是class,是interface。

聲明是:public interface Connection extends Wrapper 。

任何一個JDBC數據庫鏈接的實現類都應該實現這個接口的所有方法。好比,close。API裏的描述是,當即釋放此 Connection 對象的數據庫和 JDBC 資源,而不是等待它們被自動釋放。

熟悉Java的同窗們應該記得一點,在規範裏有個要求,就是接口的實現類必須實現接口的全部方法。可是呢,這句話還有個意思,那就是,你能夠在實現全部方法以外,再寫幾個方法。沒人會管你。

啊哈,那就有疑問了。雖然API規定了close是關閉鏈接釋放資源的。但這只是你接口的一廂情願。也許人家實現廠家以爲close方法不夠帥,要改爲closeConnection。那。。。Spring總很差傻傻的去死扣close方法來關閉鏈接吧?雖然這方法必須實現,可是可沒說必定要有內容啊。若是是空方法呢?

因此有了destroy-method這個配置項的出現。Spring說,不礙的,您老人家看哪一個爽,告訴我就行。

如今測試完了。一切都成功了。

如今來看看第二個問題。合理使用異常。

又遇到一個問題。既然測試成功了,那總得給用戶一點交待吧?難道說,測試成功了,就悶聲大發財了?顯然不合適嘛。能夠試想一下,你是程序員,而後點了個按鈕,測試。結果呢,其實是測試成功了,可是系統啥動靜都不給你。而後你傻傻的等癡癡的盼,一直等到天荒地老……嗯嗯,扯的有點遠。若是你等一個小時還不見動靜,活不見人死不見屍的,你說你會不會罵娘?

那麼怎麼通知才能保證必定有效呢?println?這個不見得必定能看到。由於別人也可能在同時輸出信息,一下就刷掉了。那麼有同窗說了,最好是能暫停一下,我輸出之後,就暫停了,不動了。

嗯,很好。

你們想一想看,輸出一大堆東西,而後此程序不動了,不繼續執行了,這是啥玩意?

這不就是異常嘛!

只有異常能保證程序員必定能看到這個信息,好比,測試成功。這就是爲何Spring要採用這種方式來通知的緣由。

這裏呢,我想更正同窗們一個習慣成天然的想法。異常不必定是通知壞消息的。異常就是異常,只要你願意,你甚至能夠在代碼執行成功的時候,throws一個Exception。異常只不過是比較激烈的一種通知方式而已。無他,僅此而已。

如今又有個問題來了。既然要測試,並且每次執行到此處的時候都要測試一下。那麼……難道都卡在這裏不走了啊?顯然更不合適啊。

熟悉log4J的同窗應該看出來了,這是log4J輸出的日誌。很明顯的,這種日誌只應當在開發期間存在,不該該在發佈期間存在。由於開發期間數據庫變更很大,好比改表啊,改數據庫配置啊。因此須要通知用戶是否成功。可是產品一旦開發完畢,正式發佈,這種信息就不該再出現,由於商業化運做的應用不容許亂動配置的,對不?

因此log4J提供了一種方法。消息級別。INFO的時候,是看不到這個異常的。實現起來也很好辦,catch了,而後不作任何處理,也就是空的catch塊。

具體實現的時候能夠在catch裏判斷一下,若是等級是INFO的話,就不作任何事。若是不是,那就按照規則去作。

結合到 「合理使用異常」 這句話來講呢,就是說,須要拋出異常的時候,就拋出。不須要拋出的時候,就不拋出。對程序員來講,在必要的時候看到一串異常信息,是最合適的事情了。

關於異常的使用,這裏不展開說了。有興趣的同窗能夠參見林銳博士的 高質量Java編程。

相關文章
相關標籤/搜索