日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

高性能jdbc封装工具 Apache Commons DbUtils 1.6(转载)

發(fā)布時間:2025/3/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 高性能jdbc封装工具 Apache Commons DbUtils 1.6(转载) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉(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è)級項(xiàng)目,Hibernate等ORM產(chǎn)品是首選,而互聯(lián)網(wǎng)領(lǐng)域,大部分開發(fā)人員往往并不會在生產(chǎn)環(huán)境中上這些ORM技術(shù),原因很簡單,要的就是效率,其次都不重要。對于剛接觸SQL和JDBC的開發(fā)人員,最引以為傲的就是希望能夠在日后編寫復(fù)雜的SQL語句,以及會使用諸如Hibernate、Ibatis等第三方持久層技術(shù),并且極力的撇清與傳統(tǒng)JDBC技術(shù)的關(guān)系,但筆者不得不認(rèn)為,這是一種普遍業(yè)界存在的“病態(tài)”!

?

如果是企業(yè)級的項(xiàng)目,尤其是跟金融相關(guān)的業(yè)務(wù),SQL語句或許會非常復(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ù)完成一條簡單的CRUD操作,這才是牛逼!是的,你沒有聽錯,互聯(lián)網(wǎng)確確實(shí)實(shí)就是這么玩還原最本質(zhì)的東西,才是追求性能的不二選擇

?

筆者本章不會提及垂直分庫、水平分區(qū)等數(shù)據(jù)庫概念,以及數(shù)據(jù)路由中間件等技術(shù)(請閱讀筆者博文《剖析淘寶TDDL—Matrix層分庫分表實(shí)現(xiàn)》),因?yàn)檫@些內(nèi)容與本章內(nèi)容無關(guān),但間接來看,筆者之前提及的單條SQL、使用JDBC完成基本的CRUD操作就可以在最大程度上滿足一個互聯(lián)網(wǎng)場景的持久層操作。以Hibernate為例,簡單來說需要經(jīng)歷HQL->SQL->DBMS等編譯過程,中間還冗余著緩存、對象等開銷,希望大家記住,封裝層次越高,性能越低!這個是無可爭議的事實(shí)。筆者希望大家接下來,暫時“忘記”掉你所會的持久層技術(shù),耐心的聽筆者為你介紹Apache的DbUtils技術(shù),或許你會有意想不到的收獲。

?

目錄

一、Apache Commons DbUtils簡介;

二、下載與安裝DbUtils;

三、使用DbUtils完成CRUD操作;

四、C3P0連接池集成DbUtils;

五、常用包、類講解;

六、自動封裝結(jié)果集;

七、事物管理;

?

一、Apache Commons DbUtils簡介;

Apache的DbUtils工具是一個輕量級的持久層解決方案,天生為性能而生,它簡單的對JDBC進(jìn)行了必要的操作封裝,讓開發(fā)人員能夠以一種高級API的方式使用JDBC技術(shù)完成原本復(fù)雜的CRUD操作。換句話說,DbUtils天生就不是一個復(fù)雜的技術(shù),它只是一個簡單的JDBC上層封裝,對開發(fā)人員而言,大概只需半小時就能夠完全掌握DbUtils技術(shù)的使用,是的,它就是這么簡單與方便,它是互聯(lián)網(wǎng)項(xiàng)目的寵兒,選擇DbUtils技術(shù)作為持久層的解決方案,或許能夠讓你從原本復(fù)雜的Hibernate操作中解脫出來,或者是你覺得Ibatis不夠好用,DbUtils也是你選擇的理由之一。總之,使用它,你將會感到驚艷,它是如此的簡單和干凈,如此的純粹和高效!并且DbUtils是采用商業(yè)友好的開源協(xié)議,大家甚至可以下載它的源碼,進(jìn)行二次開發(fā),以此滿足企業(yè)自身的需要。

?

二、下載與安裝DbUtils;

當(dāng)大家對DbUtils的項(xiàng)目背景有所了解后,接下來本節(jié)內(nèi)容筆者將會告訴你它的下載和安裝。大家可以登錄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é)會提及DbUtils與C3P0連接池的集成,因此,大家最好將C3P0所需的構(gòu)件以及數(shù)據(jù)庫驅(qū)動(筆者使用Mysql)一起添加到項(xiàng)目中。使用DbUtils時關(guān)聯(lián)的構(gòu)件,如下所示:

?

3、使用DbUtils完成CRUD操作;

廢話不多說,使用DbUtils操作數(shù)據(jù)庫之前,首先要做的事情就是獲取Connection。那么為了方便,筆者使用硬編碼的方式將數(shù)據(jù)源的配置信息coding在代碼中(生產(chǎn)環(huán)境中,有可能是配置在項(xiàng)目的配置文件中、數(shù)據(jù)庫中、Diamond中等),如下所示:

Java代碼??
  • /**?
  • ?*?數(shù)據(jù)源信息?
  • ?*??
  • ?*?@author?gaoxianglong?
  • ?*/??
  • public?class?ConnectionManager?{??
  • ????public?static?Connection?getConnection()?{??
  • ????????Connection?conn?=?null;??
  • ????????try?{??
  • ????????????Class.forName("com.mysql.jdbc.Driver");??
  • ????????????conn?=?DriverManager.getConnection(??
  • ????????????????????"jdbc:mysql://ip:port/dbName",?"userName",??
  • ????????????????????"passWord");??
  • ????????}?catch?(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????????return?conn;??
  • ????}??
  • }??
  • ?

    當(dāng)編寫好ConnectionManager之后,接下來要做的事情就是獲取Connection,然后就能夠使用DbUtils進(jìn)行CRUD操作了。或許細(xì)心的讀者已經(jīng)發(fā)現(xiàn),使用DbUtils其實(shí)是非常簡單的,需要會的不多,僅僅只需要掌握J(rèn)DBC操作以及簡單的CRUD操作即可(互聯(lián)網(wǎng)場景下同樣也是這么要求)。

    Java代碼??
  • @Test??
  • public?void?testInsert()?{??
  • ????final?String?SQL?=?"insert?into?test_1?values(?,??)";??
  • ????try?{??
  • ????????if?(null?==?conn?||?conn.isClosed())??
  • ????????????conn?=?ConnectionManager.getConnection2();??
  • ????????int?result?=?new?QueryRunner().update(conn,?SQL,?new?Object[]?{??
  • ????????????????"JohnGao1",?"123"?});??
  • ????????if?(0?<?result)??
  • ????????????System.out.println("數(shù)據(jù)插入成功...");??
  • ????}?catch?(Exception?e)?{??
  • ????????e.printStackTrace();??
  • ????}?finally?{??
  • ????????close(conn);??
  • ????}??
  • }??
  • ??
  • @Test??
  • public?void?testUpdate()?{??
  • ????final?String?SQL?=?"update?test_1?set?password=???where?username?=??";??
  • ????try?{??
  • ????????if?(null?==?conn?||?conn.isClosed())??
  • ????????????conn?=?ConnectionManager.getConnection();??
  • ????????int?result?=?new?QueryRunner().update(conn,?SQL,?new?Object[]?{??
  • ????????????????"321",?"JohnGao1"?});??
  • ????????if?(0?<?result)??
  • ????????????System.out.println("數(shù)據(jù)更新成功...");??
  • ????}?catch?(Exception?e)?{??
  • ????????e.printStackTrace();??
  • ????}?finally?{??
  • ????????close(conn);??
  • ????}??
  • }??
  • ??
  • @Test??
  • public?void?testDelete()?{??
  • ????final?String?SQL?=?"delete?from?test_1?where?username?like??";??
  • ????try?{??
  • ????????if?(null?==?conn?||?conn.isClosed())??
  • ????????????conn?=?ConnectionManager.getConnection();??
  • ????????int?result?=?new?QueryRunner().update(conn,?SQL,?"%JohnGao%");??
  • ????????if?(0?<?result)??
  • ????????????System.out.println("數(shù)據(jù)刪除成功...");??
  • ????}?catch?(Exception?e)?{??
  • ????????e.printStackTrace();??
  • ????}?finally?{??
  • ????????close(conn);??
  • ????}??
  • }??
  • ??
  • @Test??
  • public?void?testQuery()?{??
  • ????final?String?SQL?=?"select?*?from?test_1";??
  • ????try?{??
  • ????????if?(null?==?conn?||?conn.isClosed())??
  • ????????????conn?=?ConnectionManager.getConnection();??
  • ????????Test_1Bean?test1Bean?=?new?QueryRunner().query(conn,?SQL,??
  • ????????????????new?BeanHandler(Test_1Bean.class));??
  • ????????if?(null?!=?test1Bean)?{??
  • ????????????System.out.println(test1Bean.getUsername());??
  • ????????????System.out.println(test1Bean.getPassword());??
  • ????????}??
  • ????}?catch?(Exception?e)?{??
  • ????????e.printStackTrace();??
  • ????}?finally?{??
  • ????????close(conn);??
  • ????}??
  • }??
  • ?

    四、C3P0連接池集成DbUtils;

    在生產(chǎn)環(huán)境中,開發(fā)人員在對數(shù)據(jù)庫進(jìn)行CRUD操作的時候,由于數(shù)據(jù)庫的鏈接是有限的,因此不得不使用連接池來實(shí)現(xiàn)資源復(fù)用,以此降低數(shù)據(jù)庫的性能瓶頸(盡管這么說有些不太友好,因?yàn)椴l(fā)環(huán)境下,單靠連接池是不能夠解決問題的,而常用的方案更多是諸如Redis之類的內(nèi)存數(shù)據(jù)庫抗住70%傳統(tǒng)DBMS數(shù)據(jù)的受訪壓力、數(shù)據(jù)庫先做垂直分庫,再做水平分區(qū),當(dāng)然Master/Sleave是必不可少的,經(jīng)過這些步驟之后,才能夠說基本上解決了理論上可能出現(xiàn)的數(shù)據(jù)庫在高并發(fā)環(huán)境下的瓶頸)。

    ?

    廢話不多說,在之前的ConnectionManager中添加進(jìn)連接池相關(guān)的代碼,當(dāng)然為了方便,筆者同樣還是使用硬編碼的方式,如下所示:

    Java代碼??
  • public?static?ComboPooledDataSource?dataSource;??
  • static?{??
  • ????try?{??
  • ????????dataSource?=?new?ComboPooledDataSource();??
  • ????????dataSource.setUser("userName");??
  • ????????dataSource.setPassword("passWord");??
  • ????????dataSource.setJdbcUrl("jdbc:mysql://ip:port/dbName");??
  • ????????dataSource.setDriverClass("com.mysql.jdbc.Driver");??
  • ????????dataSource.setInitialPoolSize(10);??
  • ????????dataSource.setMinPoolSize(5);??
  • ????????dataSource.setMaxPoolSize(50);??
  • ????????dataSource.setMaxStatements(100);??
  • ????????dataSource.setMaxIdleTime(60);??
  • ????}?catch?(Exception?e)?{??
  • ????????e.printStackTrace();??
  • ????}??
  • }??
  • ??
  • /**?
  • ?*?從連接池中獲取數(shù)據(jù)源鏈接?
  • ?*??
  • ?*?@author?gaoxianglong?
  • ?*??
  • ?*?@return?Connection?數(shù)據(jù)源鏈接?
  • ?*/??
  • public?static?Connection?getConnection2()?{??
  • ????Connection?conn?=?null;??
  • ????if?(null?!=?dataSource)?{??
  • ????????try?{??
  • ????????????conn?=?dataSource.getConnection();??
  • ????????}?catch?(SQLException?e)?{??
  • ????????????e.printStackTrace();??
  • ????????}??
  • ????}??
  • ????return?conn;??
  • }??
  • ?

    當(dāng)成功在ConnectionManager中添加好所需的C3P0連接池配置后,接下來要做的事情就是考慮如何使用C3P0與DbUtils之間的集成。其實(shí)最簡單的做法就是直接將之前獲取Connection的getConnection()方法更換為上述代碼中的getConnection2()即可,同樣可以使用在創(chuàng)建QueryRunner實(shí)例時,將數(shù)據(jù)源的DataSource傳遞過去,這樣即可避免在執(zhí)行CRUD操作時,還需要在方法中指明Connection。

    ?

    當(dāng)然究竟應(yīng)該怎么做,完全取決于你自己,如果希望方便,那么筆者建議你在創(chuàng)建QueryRunner實(shí)例時,直接將C3P0的DataSource傳遞過去,但這樣做的弊端很明顯,如果在特殊的場景下,需要手動控制事物時,那么這種操作是極其不便的,因?yàn)镃onnection并不可控。那么為了解決事物控制的問題,當(dāng)然是Connection可控最好。

    ?

    五、常用包、類講解;

    相信大家已經(jīng)從上述DbUtils的CRUD示例中發(fā)現(xiàn)了QueryRunner的身影,那么筆者接下來就將會針對DbUtils中諸如QueryRunner等常用類型進(jìn)行深入講解。

    ?

    在DbUtils中,最常用的3個包為org.apache.commons.dbutils、org.apache.commons.dbutils.handlers以及org.apache.commons.dbutils.wrappers。

    org.apache.commons.dbutils包下的常用類,如下所示:

    1、DbUtils : 提供如關(guān)閉連接、裝載 JDBC 驅(qū)動程序等常規(guī)工作的工具類;
    2、QueryRunner : 該類簡單化了 SQL 查詢,它常與與 ResultSetHandler 組合在一起使用;

    org.apache.commons.dbutils.handlers包下的常用類,如下所示:

    1、ArrayHandler :將ResultSet中第一行的數(shù)據(jù)轉(zhuǎn)化成對象數(shù)組;
    2、ArrayListHandler:將ResultSet中所有的數(shù)據(jù)轉(zhuǎn)化成List,List中存放的是Object[];
    3、BeanHandler :將ResultSet中第一行的數(shù)據(jù)轉(zhuǎn)化成類對象;
    4、BeanListHandler :將ResultSet中所有的數(shù)據(jù)轉(zhuǎn)化成List,List中存放的是類對象;
    5、ColumnListHandler :將ResultSet中某一列的數(shù)據(jù)存成List,List中存放的是Object對象;
    6、KeyedHandler :將ResultSet中存成映射,key為某一列對應(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 :該類是用來對sql語句執(zhí)行完成之后的的數(shù)值進(jìn)行null的替換;
    2、StringTrimmedResultSet :去除ResultSet中中字段的左右空格;

    ?

    六、自動封裝結(jié)果集;

    在org.apache.commons.dbutils.handlers包下的類型,大部分都是與查詢結(jié)果集相關(guān)的。試想一下,利用傳統(tǒng)的JDBC進(jìn)行查詢時,返回的數(shù)據(jù)我們需要對ResultSet進(jìn)行迭代,這是相當(dāng)麻煩的,且不利于維護(hù),因?yàn)槲覀冃枰?span style="color:#800000;">手動編寫與之相關(guān)的數(shù)據(jù)封裝。但是使用DbUtils之后,我們要做的事情僅僅只是告訴DbUtils我們需要什么樣的數(shù)據(jù)即可,關(guān)于數(shù)據(jù)封裝這種通用的控制邏輯,則無需開發(fā)人員參與,這極大的節(jié)省了開發(fā)人員的時間,提升了生產(chǎn)效率。

    ?

    簡單來說,筆者在開發(fā)過程中使用最廣泛的就是BeanListHandler以及MapListHandler 封裝的結(jié)果集。簡單來說,BeanListHandler將會查詢后的數(shù)據(jù)封裝到一個對應(yīng)的POJO中(可以看做是一個無狀態(tài)的實(shí)體Bean),MapListHandler 會將查詢后的數(shù)據(jù)封裝為一個List,List中存儲的就是一個個的Map集合,通過key-value的方式獲取封裝后的數(shù)據(jù)集。先來看看MapListHandler 的使用,如下所示:

    Java代碼??
  • @Test??
  • public?void?testQuery4()?{??
  • ????final?String?SQL?=?"select?*?from?test_1?where?username?like??";??
  • ????try?{??
  • ????????if?(null?==?conn?||?conn.isClosed())??
  • ????????????conn?=?ConnectionManager.getConnection2();??
  • ????????List<Map<String,?Object>>?values?=?new?QueryRunner().query(conn,??
  • ????????????????SQL,?new?Object[]?{?"%JohnGao%"?},?new?MapListHandler());??
  • ????????if?(null?!=?values)?{??
  • ????????????for?(int?i?=?0;?i?<?values.size();?i++)?{??
  • ????????????????Map<String,?Object>?map?=?values.get(i);??
  • ????????????????System.out.println(map.get("username"));??
  • ????????????????System.out.println(map.get("password"));??
  • ????????????}??
  • ????????}??
  • ????}?catch?(Exception?e)?{??
  • ????????e.printStackTrace();??
  • ????}?finally?{??
  • ????????close(conn);??
  • ????}??
  • }??
  • ?

    如果你喜歡類似于實(shí)體Bean的操作方式,那么BeanListHandler無疑使最好的選擇。一旦我們使用BeanListHandler作為數(shù)據(jù)返回后的結(jié)果集封裝,那么DbUtils便會將查詢后的結(jié)果集一個字段一個字段的映射到指定的POJO中,當(dāng)然前提就是字段名稱是必須一致的,否則DbUtils將無法完成數(shù)據(jù)封裝。BeanListHandler的使用示例,如下所示:

    Java代碼??
  • @Test??
  • public?void?testQuery3()?{??
  • ????final?String?SQL?=?"select?*?from?test_1?where?username?like??";??
  • ????try?{??
  • ????????if?(null?==?conn?||?conn.isClosed())??
  • ????????????conn?=?ConnectionManager.getConnection();??
  • ????????List<Test_1Bean>?test1Beans?=?new?QueryRunner().query(conn,?SQL,??
  • ????????????????new?Object[]?{?"%JohnGao%"?},?new?BeanListHandler(??
  • ????????????????????????Test_1Bean.class));??
  • ????????if?(null?!=?test1Beans)?{??
  • ????????????for?(Test_1Bean?test1Bean?:?test1Beans)?{??
  • ????????????????System.out.println(test1Bean.getUsername());??
  • ????????????????System.out.println(test1Bean.getPassword());??
  • ????????????}??
  • ????????}??
  • ????}?catch?(Exception?e)?{??
  • ????????e.printStackTrace();??
  • ????}?finally?{??
  • ????????close(conn);??
  • ????}??
  • }??
  • ?

    在此大家需要注意,為了方便演示,筆者在此并沒有提供對應(yīng)的POJO。如果有需要,大家可以編寫一個與數(shù)據(jù)庫表字段相同的POJO來完成查詢結(jié)果集的字段映射封裝操作。

    ?

    七、事物管理;

    說起事物管理,這其實(shí)是一個非常復(fù)雜與繁瑣,且是最容易出錯的場景,尤其是在手動管理事物操作上。當(dāng)然本節(jié)所提及的事物管理仍然是建立在基于手動管理的事物操作上。對于JDBC操作,如果希望事物不要手動提交,那么在獲取Connection的時候,一定需要將設(shè)置conn.setAutoCommit(false);這樣一來事物就不會自動進(jìn)行提交,當(dāng)我們手動執(zhí)行conn.commit()方法的時候,事物才會進(jìn)行提交。這種方式對于DbUtils其實(shí)是一樣的,之前也說過,DbUtils僅僅只是對JDBC做了一個輕量級的上層封裝,那么必然可以和JDBC進(jìn)行混用,一旦我們在程序中設(shè)定了事物后,接下來的事物管理操作就依賴與開發(fā)人員自身了,DbUtils將不會再參與事物的管理。

    ?

    對于大多數(shù)開發(fā)人員而言,事物控制的不好,將會導(dǎo)致業(yè)務(wù)出現(xiàn)問題,臟數(shù)據(jù)等情況是非常常見的,但從另一個層面來說,手動的事物管理其實(shí)是最靈活和方便的。在此需要提醒大家,如果是使用Mysql數(shù)據(jù)庫,只有將數(shù)據(jù)庫引擎設(shè)置為InnoDB后,才會支持事物

    ?

    最后筆者在啰嗦一下,使用完資源后,我們一定要記得及時釋放掉資源,以此避免無用資源長時間掛起。那么在DbUtils中,你將有2種方式結(jié)束掉Connection,第一個是使用DbUtils.close()方法。其次,你將可以直接使用close()方法關(guān)閉Connection的鏈接

    轉(zhuǎn)載于:https://www.cnblogs.com/firstdream/p/4892184.html

    總結(jié)

    以上是生活随笔為你收集整理的高性能jdbc封装工具 Apache Commons DbUtils 1.6(转载)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。