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