高性能jdbc封装工具 Apache Commons DbUtils 1.6(转载)
轉(zhuǎn)載自原文地址:http://gao-xianglong.iteye.com/blog/2166444
前言
關(guān)于Apache的DbUtils中間件或許了解的人并不多,大部分開發(fā)人員在生成環(huán)境中更多的是依靠Hibernate、Ibatis、Spring JDBC、JPA等大廠提供的持久層技術(shù)解決方案,或者是企業(yè)內(nèi)部自己研發(fā)的持久層技術(shù)。但無論如何,使用這些技術(shù)的初衷和本質(zhì)都是為了能夠減少企業(yè)開發(fā)成本,提高生產(chǎn)效率,降低耦合。
?
放眼企業(yè)級(jí)項(xiàng)目,Hibernate等ORM產(chǎn)品是首選,而互聯(lián)網(wǎng)領(lǐng)域,大部分開發(fā)人員往往并不會(huì)在生產(chǎn)環(huán)境中上這些ORM技術(shù),原因很簡(jiǎn)單,要的就是效率,其次都不重要。對(duì)于剛接觸SQL和JDBC的開發(fā)人員,最引以為傲的就是希望能夠在日后編寫復(fù)雜的SQL語句,以及會(huì)使用諸如Hibernate、Ibatis等第三方持久層技術(shù),并且極力的撇清與傳統(tǒng)JDBC技術(shù)的關(guān)系,但筆者不得不認(rèn)為,這是一種普遍業(yè)界存在的“病態(tài)”!
?
如果是企業(yè)級(jí)的項(xiàng)目,尤其是跟金融相關(guān)的業(yè)務(wù),SQL語句或許會(huì)非常復(fù)雜,并且關(guān)聯(lián)著事物。但互聯(lián)網(wǎng)項(xiàng)目卻并非如此,在互聯(lián)網(wǎng)項(xiàng)目中,看你牛不牛逼并不是取決于你能否寫出一條復(fù)雜的SQL語句,而是看你能否將原本一條復(fù)雜的SQL語句拆散成單條SQL,一句一句的執(zhí)行;并且脫離Hibernate等ORM產(chǎn)品后,能否使用傳統(tǒng)的JDBC技術(shù)完成一條簡(jiǎn)單的CRUD操作,這才是牛逼!是的,你沒有聽錯(cuò),互聯(lián)網(wǎng)確確實(shí)實(shí)就是這么玩,還原最本質(zhì)的東西,才是追求性能的不二選擇。
?
筆者本章不會(huì)提及垂直分庫(kù)、水平分區(qū)等數(shù)據(jù)庫(kù)概念,以及數(shù)據(jù)路由中間件等技術(shù)(請(qǐng)閱讀筆者博文《剖析淘寶TDDL—Matrix層分庫(kù)分表實(shí)現(xiàn)》),因?yàn)檫@些內(nèi)容與本章內(nèi)容無關(guān),但間接來看,筆者之前提及的單條SQL、使用JDBC完成基本的CRUD操作就可以在最大程度上滿足一個(gè)互聯(lián)網(wǎng)場(chǎng)景的持久層操作。以Hibernate為例,簡(jiǎn)單來說需要經(jīng)歷HQL->SQL->DBMS等編譯過程,中間還冗余著緩存、對(duì)象等開銷,希望大家記住,封裝層次越高,性能越低!這個(gè)是無可爭(zhēng)議的事實(shí)。筆者希望大家接下來,暫時(shí)“忘記”掉你所會(huì)的持久層技術(shù),耐心的聽筆者為你介紹Apache的DbUtils技術(shù),或許你會(huì)有意想不到的收獲。
?
目錄
一、Apache Commons DbUtils簡(jiǎn)介;
二、下載與安裝DbUtils;
三、使用DbUtils完成CRUD操作;
四、C3P0連接池集成DbUtils;
五、常用包、類講解;
六、自動(dòng)封裝結(jié)果集;
七、事物管理;
?
一、Apache Commons DbUtils簡(jiǎn)介;
Apache的DbUtils工具是一個(gè)輕量級(jí)的持久層解決方案,天生為性能而生,它簡(jiǎn)單的對(duì)JDBC進(jìn)行了必要的操作封裝,讓開發(fā)人員能夠以一種高級(jí)API的方式使用JDBC技術(shù)完成原本復(fù)雜的CRUD操作。換句話說,DbUtils天生就不是一個(gè)復(fù)雜的技術(shù),它只是一個(gè)簡(jiǎn)單的JDBC上層封裝,對(duì)開發(fā)人員而言,大概只需半小時(shí)就能夠完全掌握DbUtils技術(shù)的使用,是的,它就是這么簡(jiǎn)單與方便,它是互聯(lián)網(wǎng)項(xiàng)目的寵兒,選擇DbUtils技術(shù)作為持久層的解決方案,或許能夠讓你從原本復(fù)雜的Hibernate操作中解脫出來,或者是你覺得Ibatis不夠好用,DbUtils也是你選擇的理由之一。總之,使用它,你將會(huì)感到驚艷,它是如此的簡(jiǎn)單和干凈,如此的純粹和高效!并且DbUtils是采用商業(yè)友好的開源協(xié)議,大家甚至可以下載它的源碼,進(jìn)行二次開發(fā),以此滿足企業(yè)自身的需要。
?
二、下載與安裝DbUtils;
當(dāng)大家對(duì)DbUtils的項(xiàng)目背景有所了解后,接下來本節(jié)內(nèi)容筆者將會(huì)告訴你它的下載和安裝。大家可以登錄http://commons.apache.org/站點(diǎn)下載DbUtils工具的最新版本,筆者使用的版本為1.6.0,在此大家需要注意,為了避免在開發(fā)過程中出現(xiàn)異常,建議大家下載、使用與筆者本篇博文一致的版本。
?
當(dāng)大家成功下載好DbUtils相關(guān)的構(gòu)件后,我們可以將其添加到項(xiàng)目中的ClassPath目錄下,當(dāng)然筆者后續(xù)小節(jié)會(huì)提及DbUtils與C3P0連接池的集成,因此,大家最好將C3P0所需的構(gòu)件以及數(shù)據(jù)庫(kù)驅(qū)動(dòng)(筆者使用Mysql)一起添加到項(xiàng)目中。使用DbUtils時(shí)關(guān)聯(lián)的構(gòu)件,如下所示:
?
3、使用DbUtils完成CRUD操作;
廢話不多說,使用DbUtils操作數(shù)據(jù)庫(kù)之前,首先要做的事情就是獲取Connection。那么為了方便,筆者使用硬編碼的方式將數(shù)據(jù)源的配置信息coding在代碼中(生產(chǎn)環(huán)境中,有可能是配置在項(xiàng)目的配置文件中、數(shù)據(jù)庫(kù)中、Diamond中等),如下所示:
Java代碼???
當(dāng)編寫好ConnectionManager之后,接下來要做的事情就是獲取Connection,然后就能夠使用DbUtils進(jìn)行CRUD操作了。或許細(xì)心的讀者已經(jīng)發(fā)現(xiàn),使用DbUtils其實(shí)是非常簡(jiǎn)單的,需要會(huì)的不多,僅僅只需要掌握J(rèn)DBC操作以及簡(jiǎn)單的CRUD操作即可(互聯(lián)網(wǎng)場(chǎng)景下同樣也是這么要求)。
Java代碼???
四、C3P0連接池集成DbUtils;
在生產(chǎn)環(huán)境中,開發(fā)人員在對(duì)數(shù)據(jù)庫(kù)進(jìn)行CRUD操作的時(shí)候,由于數(shù)據(jù)庫(kù)的鏈接是有限的,因此不得不使用連接池來實(shí)現(xiàn)資源復(fù)用,以此降低數(shù)據(jù)庫(kù)的性能瓶頸(盡管這么說有些不太友好,因?yàn)椴l(fā)環(huán)境下,單靠連接池是不能夠解決問題的,而常用的方案更多是諸如Redis之類的內(nèi)存數(shù)據(jù)庫(kù)抗住70%傳統(tǒng)DBMS數(shù)據(jù)的受訪壓力、數(shù)據(jù)庫(kù)先做垂直分庫(kù),再做水平分區(qū),當(dāng)然Master/Sleave是必不可少的,經(jīng)過這些步驟之后,才能夠說基本上解決了理論上可能出現(xiàn)的數(shù)據(jù)庫(kù)在高并發(fā)環(huán)境下的瓶頸)。
?
廢話不多說,在之前的ConnectionManager中添加進(jìn)連接池相關(guān)的代碼,當(dāng)然為了方便,筆者同樣還是使用硬編碼的方式,如下所示:
Java代碼???
當(dāng)成功在ConnectionManager中添加好所需的C3P0連接池配置后,接下來要做的事情就是考慮如何使用C3P0與DbUtils之間的集成。其實(shí)最簡(jiǎn)單的做法就是直接將之前獲取Connection的getConnection()方法更換為上述代碼中的getConnection2()即可,同樣可以使用在創(chuàng)建QueryRunner實(shí)例時(shí),將數(shù)據(jù)源的DataSource傳遞過去,這樣即可避免在執(zhí)行CRUD操作時(shí),還需要在方法中指明Connection。
?
當(dāng)然究竟應(yīng)該怎么做,完全取決于你自己,如果希望方便,那么筆者建議你在創(chuàng)建QueryRunner實(shí)例時(shí),直接將C3P0的DataSource傳遞過去,但這樣做的弊端很明顯,如果在特殊的場(chǎng)景下,需要手動(dòng)控制事物時(shí),那么這種操作是極其不便的,因?yàn)镃onnection并不可控。那么為了解決事物控制的問題,當(dāng)然是Connection可控最好。
?
五、常用包、類講解;
相信大家已經(jīng)從上述DbUtils的CRUD示例中發(fā)現(xiàn)了QueryRunner的身影,那么筆者接下來就將會(huì)針對(duì)DbUtils中諸如QueryRunner等常用類型進(jìn)行深入講解。
?
在DbUtils中,最常用的3個(gè)包為org.apache.commons.dbutils、org.apache.commons.dbutils.handlers以及org.apache.commons.dbutils.wrappers。
org.apache.commons.dbutils包下的常用類,如下所示:
1、DbUtils : 提供如關(guān)閉連接、裝載 JDBC 驅(qū)動(dòng)程序等常規(guī)工作的工具類;
2、QueryRunner : 該類簡(jiǎn)單化了 SQL 查詢,它常與與 ResultSetHandler 組合在一起使用;
org.apache.commons.dbutils.handlers包下的常用類,如下所示:
1、ArrayHandler :將ResultSet中第一行的數(shù)據(jù)轉(zhuǎn)化成對(duì)象數(shù)組;
2、ArrayListHandler:將ResultSet中所有的數(shù)據(jù)轉(zhuǎn)化成List,List中存放的是Object[];
3、BeanHandler :將ResultSet中第一行的數(shù)據(jù)轉(zhuǎn)化成類對(duì)象;
4、BeanListHandler :將ResultSet中所有的數(shù)據(jù)轉(zhuǎn)化成List,List中存放的是類對(duì)象;
5、ColumnListHandler :將ResultSet中某一列的數(shù)據(jù)存成List,List中存放的是Object對(duì)象;
6、KeyedHandler :將ResultSet中存成映射,key為某一列對(duì)應(yīng)為Map。Map中存放的是數(shù)據(jù);
7、MapHandler :將ResultSet中第一行的數(shù)據(jù)存成Map映射;
8、MapListHandler :將ResultSet中所有的數(shù)據(jù)存成List。List中存放的是Map;
9、ScalarHandler :將ResultSet中一條記錄的其中某一列的數(shù)據(jù)存成Object;
org.apache.commons.dbutils.wrappers包下的常用類,如下所示:
1、SqlNullCheckedResultSet :該類是用來對(duì)sql語句執(zhí)行完成之后的的數(shù)值進(jìn)行null的替換;
2、StringTrimmedResultSet :去除ResultSet中中字段的左右空格;
?
六、自動(dòng)封裝結(jié)果集;
在org.apache.commons.dbutils.handlers包下的類型,大部分都是與查詢結(jié)果集相關(guān)的。試想一下,利用傳統(tǒng)的JDBC進(jìn)行查詢時(shí),返回的數(shù)據(jù)我們需要對(duì)ResultSet進(jìn)行迭代,這是相當(dāng)麻煩的,且不利于維護(hù),因?yàn)槲覀冃枰?span style="color:#800000;">手動(dòng)編寫與之相關(guān)的數(shù)據(jù)封裝。但是使用DbUtils之后,我們要做的事情僅僅只是告訴DbUtils我們需要什么樣的數(shù)據(jù)即可,關(guān)于數(shù)據(jù)封裝這種通用的控制邏輯,則無需開發(fā)人員參與,這極大的節(jié)省了開發(fā)人員的時(shí)間,提升了生產(chǎn)效率。
?
簡(jiǎn)單來說,筆者在開發(fā)過程中使用最廣泛的就是BeanListHandler以及MapListHandler 封裝的結(jié)果集。簡(jiǎn)單來說,BeanListHandler將會(huì)查詢后的數(shù)據(jù)封裝到一個(gè)對(duì)應(yīng)的POJO中(可以看做是一個(gè)無狀態(tài)的實(shí)體Bean),MapListHandler 會(huì)將查詢后的數(shù)據(jù)封裝為一個(gè)List,List中存儲(chǔ)的就是一個(gè)個(gè)的Map集合,通過key-value的方式獲取封裝后的數(shù)據(jù)集。先來看看MapListHandler 的使用,如下所示:
Java代碼???
如果你喜歡類似于實(shí)體Bean的操作方式,那么BeanListHandler無疑使最好的選擇。一旦我們使用BeanListHandler作為數(shù)據(jù)返回后的結(jié)果集封裝,那么DbUtils便會(huì)將查詢后的結(jié)果集一個(gè)字段一個(gè)字段的映射到指定的POJO中,當(dāng)然前提就是字段名稱是必須一致的,否則DbUtils將無法完成數(shù)據(jù)封裝。BeanListHandler的使用示例,如下所示:
Java代碼???
在此大家需要注意,為了方便演示,筆者在此并沒有提供對(duì)應(yīng)的POJO。如果有需要,大家可以編寫一個(gè)與數(shù)據(jù)庫(kù)表字段相同的POJO來完成查詢結(jié)果集的字段映射封裝操作。
?
七、事物管理;
說起事物管理,這其實(shí)是一個(gè)非常復(fù)雜與繁瑣,且是最容易出錯(cuò)的場(chǎng)景,尤其是在手動(dòng)管理事物操作上。當(dāng)然本節(jié)所提及的事物管理仍然是建立在基于手動(dòng)管理的事物操作上。對(duì)于JDBC操作,如果希望事物不要手動(dòng)提交,那么在獲取Connection的時(shí)候,一定需要將設(shè)置conn.setAutoCommit(false);這樣一來事物就不會(huì)自動(dòng)進(jìn)行提交,當(dāng)我們手動(dòng)執(zhí)行conn.commit()方法的時(shí)候,事物才會(huì)進(jìn)行提交。這種方式對(duì)于DbUtils其實(shí)是一樣的,之前也說過,DbUtils僅僅只是對(duì)JDBC做了一個(gè)輕量級(jí)的上層封裝,那么必然可以和JDBC進(jìn)行混用,一旦我們?cè)诔绦蛑性O(shè)定了事物后,接下來的事物管理操作就依賴與開發(fā)人員自身了,DbUtils將不會(huì)再參與事物的管理。
?
對(duì)于大多數(shù)開發(fā)人員而言,事物控制的不好,將會(huì)導(dǎo)致業(yè)務(wù)出現(xiàn)問題,臟數(shù)據(jù)等情況是非常常見的,但從另一個(gè)層面來說,手動(dòng)的事物管理其實(shí)是最靈活和方便的。在此需要提醒大家,如果是使用Mysql數(shù)據(jù)庫(kù),只有將數(shù)據(jù)庫(kù)引擎設(shè)置為InnoDB后,才會(huì)支持事物!
?
最后筆者在啰嗦一下,使用完資源后,我們一定要記得及時(shí)釋放掉資源,以此避免無用資源長(zhǎng)時(shí)間掛起。那么在DbUtils中,你將有2種方式結(jié)束掉Connection,第一個(gè)是使用DbUtils.close()方法。其次,你將可以直接使用close()方法關(guān)閉Connection的鏈接
轉(zhuǎn)載于:https://www.cnblogs.com/firstdream/p/4892184.html
總結(jié)
以上是生活随笔為你收集整理的高性能jdbc封装工具 Apache Commons DbUtils 1.6(转载)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (软件工程复习核心重点)第七章软件维护-
- 下一篇: 汇编四则运算