從設計不足的JDBC,說到數(shù)據(jù)庫鏈接池
JDBC是Java里邊一個很重要的組成部分,現(xiàn)代的很多軟件應用,都和數(shù)據(jù)庫相關,因此,JDBC起著日益重要的作用。即便一個Java開發(fā)工程 師不怎么直接使用JDBC,而是使用ORM等框架,但是這些框架也是給予JDBC包裝而來的。因此,JDBC的不足,也給這些ORM還有數(shù)據(jù)庫連接池組件 帶來了很大的不便。
我們知道,Java的Statement(和PreparedStatement),在execute查詢和執(zhí)行語句時,都需要檢查 SQLException,這個SQLException實際上表示的涵義太寬泛了,這也就是我在題目中提到的“缺乏設計”,實際上,一個 Statement,執(zhí)行的時候出錯,有著多種可能,應該把這些錯誤分一下類來設計,這樣表示的更清楚。
比如。在Statement去執(zhí)行一個SQL時,很有可能是其所依賴的Connection被關閉了,這個時候,執(zhí)行語句跑出的SQLException實際上是不合適的,應該是SQLConnectionException;
比如,要去一個不存在的表中select,執(zhí)行時,跑出SQLException實際上是很對的;
但是我們看到,不管JDBC的版本怎么提升,從來也沒有出現(xiàn)過SQLConnectionException這種東西,不管SQL執(zhí)行時除了什么錯,都是SQLExceptin。這非常像當初剛剛學Java時,寫一個接口,通通聲明為拋出Exception....
那么這個問題會影響到什么呢?如果每次使用都是直接創(chuàng)建連接,使用并且關閉還好,遇到異常就關閉就完事了,但是我們知道,目前很多開發(fā)使用的都是連接池,池化連接的close不是真正的關閉,而是將連接送回池中。
例如代碼為:
- Connection conn = null;
- try{
- conn = pool.getConnection();
- conn.....
- }catch(Exception ex){
- ...
- }finally{
- if(conn!=null)conn.close();
- }
題在于,如果出現(xiàn)異常了(一般是SQLException),應該怎么處理?按照邏輯,應該是如果是SQL查了一個不存在的表之類的,當然是連接回池,如果是連接壞了,當然是直接關閉。
但是現(xiàn)在我們能判斷嗎?因為只有SQLException,我們判斷不出來。
根據(jù)SQLException的Message判斷嗎?不同數(shù)據(jù)庫,Message是不同的。。。
還有可恨的,大多數(shù)數(shù)據(jù)庫連接池,實際上是不向外提供“真正關閉一個連接”這個操作時,當然,這么做的考慮是為了屏蔽池化連接和直接創(chuàng)建的連接的區(qū)別,但是,這個接口封上之后,面對的這種問題應該怎么處理呢?
目前。大多數(shù)連接池也有一種辦法解決,就是配置一個SQL,每次取出一個連接用的時候,都先執(zhí)行一下,如果出錯,表示連接壞了,連接池(連接池自身 當然能夠真正關閉連接)真正關閉這個連接,給一個新的連接供外部請求者使用。但這是個拙劣的方法,因為一個SQL意味著和數(shù)據(jù)庫的一個TCP交互,性能的 損耗是客觀存在的,高并發(fā)、高效率的系統(tǒng)不應該用這種方法。
如果JDBC能夠區(qū)分,那么將省去了很多麻煩,不管在連接池內部處理還是外部處理,至少都是符合邏輯的。在這里也建議使用一些開源數(shù)據(jù)庫連接池組件 的朋友們,如果你要選擇一種連接池,一定注意這種連接池這種情況下的處理,是怎樣設計實現(xiàn)的,這一是表明了開發(fā)者考慮問題是否周全,而是關乎系統(tǒng)效率和穩(wěn) 定性。
可能有的朋友會問,Java不會這么缺乏好的設計嗎?我其實也不希望Java有這種缺陷,希望有一種好的機制來解決我的問題,但是很可惜沒有看到。 之前曾經(jīng)花了很大的力氣研究Java的源碼,曾經(jīng)認為Java有很多地方值得學習,所以去研讀。結果發(fā)現(xiàn),有很多代碼非常好,同時也發(fā)現(xiàn)很多代碼很糟糕; 甚至不是實現(xiàn)代碼的問題,而是設計時粗枝大葉。
一時、一天細心容易做到,但是在職業(yè)生涯中總保持細心、周全的考慮問題并不是件容易的事情,所以雖然覺得這里有問題,但是也不是嘲諷或者責難別人, 而是希望Java早一天認識到這些基礎庫的問題,對這些東西進行一些梳理和改進,做好基礎語言,別盲目的追逐熱點,把高樓大廈建立在沙灘上。