實(shí)施Jakarta Commons-DbUtils
作者: Builder.comMonday, April 26 2004 4:43 PM
JDBC碼是Java譯碼的一個(gè)部分,它給已寫(xiě)的編碼帶來(lái)了數(shù)量驚人的重復(fù)。另外,JDBC碼幾乎會(huì)經(jīng)常性的帶來(lái)一些低級(jí)錯(cuò)誤。寫(xiě)出好的JDBC編碼并不難,但是很痛苦。
![]() |
![]() |
DbUtils組件是一個(gè)精密而簡(jiǎn)單的組件,它并不做什么復(fù)雜的事而僅僅只是使很多的JDBC任務(wù)對(duì)開(kāi)發(fā)者來(lái)說(shuō)變得稍容易一點(diǎn)。盡管這時(shí)候很多持久框架和包都可以用來(lái)使數(shù)據(jù)持久變得更容易,然而JDBC仍然是大多數(shù)Java和Java2企業(yè)版(J2EE)開(kāi)發(fā)者賴(lài)以生存的工具。因此,任何能讓使用JDBC工作更容易的東西都是好消息。
DbUtils可以免費(fèi)下載
,它不依賴(lài)于任何其它的通用組件而只是依賴(lài)下面這些:- Java Development Kit (JDK) 1.2 (or later)
- JDBC 2.0 (or later)
DbUtils文檔并不是最好的,但是足以使你的工作正常進(jìn)行。在下一節(jié),你會(huì)看到DbUtils中最有用的類(lèi)以及一些關(guān)于它們的用法的例子。你應(yīng)該能夠很容易地使用這些編碼和例子,然后能夠馬上在你自己的項(xiàng)目中開(kāi)始使用DbUtils。我將會(huì)集中精力于兩個(gè)類(lèi)(org.apache.commons.dbutils.DbUtils 和org.apache.commons.dbutils.QueryRunner)和一個(gè)接口(org.apache.commons.dbutils.ResultSethandler).在我給你們一些關(guān)于它們的用法的例子之前,讓我們深入DbUtils里面來(lái)仔細(xì)看看它給我們提供了些什么。
DbUtils
DbUtils是一個(gè)為做一些諸如關(guān)閉連接、裝載JDBC驅(qū)動(dòng)程序之類(lèi)的常規(guī)工作提供有用方法的類(lèi),它里面所有的方法都是靜態(tài)的。這個(gè)類(lèi)里的重要方法有:
- close:DbUtils類(lèi)提供了三個(gè)重載的關(guān)閉方法。這些方法檢查所提供的參數(shù)是不是NULL,如果不是的話(huà),它們就關(guān)閉連接、聲明和結(jié)果集(ResultSet)。
- CloseQuietly: CloseQuietly這一方法不僅能在連接、聲明或者結(jié)果集(ResultSet)為NULL情況下避免關(guān)閉,還能隱藏一些在程序中拋出的SQLEeception。如果你不想捕捉這些異常的話(huà),這對(duì)你是非常有用的。在重載CloseQuietly方法時(shí),特別有用的一個(gè)方法是closeQuietly(Connection conn,Statement stmt,ResultSet rs),這是因?yàn)樵诖蠖鄶?shù)情況下,連接、聲明和結(jié)果集(ResultSet)是你要用的三樣?xùn)|西,而且在最后的塊你必須關(guān)閉它們。使用這一方法,你最后的塊就可以只需要調(diào)用這一方法即可。
- CommitAndCloseQuietly(Connection conn):這一方法用來(lái)提交連接,然后關(guān)閉連接,并且在關(guān)閉連接時(shí)不向上拋出在關(guān)閉時(shí)發(fā)生的一些SQL異常。
- LoadDriver(String driveClassName): 這一方法裝載并注冊(cè)JDBC驅(qū)動(dòng)程序,如果成功就返回TRUE。使用這種方法,你不需要去捕捉這個(gè)異常ClassNotFoundException。使用loadDrive方法,編碼就變得更容易理解,你也就得到了一個(gè)很好的Boolean返回值,這個(gè)返回值會(huì)告訴你驅(qū)動(dòng)類(lèi)是不是已經(jīng)加載成功了。
ResultSetHandler
![]() |
![]() |
正如它的名字所提示的,這一接口執(zhí)行處理一個(gè)jaca.sql.ResultSet,將數(shù)據(jù)轉(zhuǎn)變并處理為任何一種形式,這樣有益于其應(yīng)用而且使用起來(lái)更容易。這一組件提供了ArrayHandler, ArrayListHandler, BeanHandler, BeanListHandler, MapHandler, MapListHandler, and ScalarHandler等執(zhí)行程序。
ResultSetHandler接口提供了一個(gè)單獨(dú)的方法:Object handle (java.sql.ResultSet .rs)。因此任何ResultSetHandler 的執(zhí)行需要一個(gè)結(jié)果集(ResultSet)作為參數(shù)傳入,然后才能處理這個(gè)結(jié)果集,再返回一個(gè)對(duì)象。因?yàn)榉祷仡?lèi)型是java.lang.Object,所以除了不能返回一個(gè)原始的Java類(lèi)型之外,其它的返回類(lèi)型并沒(méi)有什么限制。如果你發(fā)現(xiàn)這七個(gè)執(zhí)行程序中沒(méi)有任何一個(gè)提供了你想要的服務(wù),你可以自己寫(xiě)執(zhí)行程序并使用它。
QreryRunner
這個(gè)類(lèi)使執(zhí)行SQL查詢(xún)簡(jiǎn)單化了,它與ResultSetHandler串聯(lián)在一起有效地履行著一些平常的任務(wù),它能夠大大減少你所要寫(xiě)的編碼。QueryRunner類(lèi)提供了兩個(gè)構(gòu)造器:其中一個(gè)是一個(gè)空構(gòu)造器,另一個(gè)則拿一個(gè) javax.sql.DataSource 來(lái)作為參數(shù)。因此,在你不用為一個(gè)方法提供一個(gè)數(shù)據(jù)庫(kù)連接來(lái)作為參數(shù)的情況下,提供給構(gòu)造器的數(shù)據(jù)源(DataSource) 被用來(lái)獲得一個(gè)新的連接并將繼續(xù)進(jìn)行下去。
這一類(lèi)中的重要方法包括以下這些:
- query(Connection conn, String sql, Object[] params, ResultSetHandler rsh):這一方法執(zhí)行一個(gè)選擇查詢(xún),在這個(gè)查詢(xún)中,對(duì)象陣列的值被用來(lái)作為查詢(xún)的置換參數(shù)。這一方法內(nèi)在地處理PreparedStatement 和ResultSet 的創(chuàng)建和關(guān)閉。ResultSetHandler對(duì)把從 ResultSet得來(lái)的數(shù)據(jù)轉(zhuǎn)變成一個(gè)更容易的或是應(yīng)用程序特定的格式來(lái)使用。
- query(String sql, Object[] params, ResultSetHandler rsh):這幾乎與第一種方法一樣;唯一的不同在于它不將數(shù)據(jù)庫(kù)連接提供給方法,并且它是從提供給構(gòu)造器的數(shù)據(jù)源(DataSource) 或使用的setDAtaSource 方法中重新獲得的。
- query(Connection conn, String sql, ResultSetHandler rsh):這執(zhí)行一個(gè)不要參數(shù)的選擇查詢(xún)。
- update(Connection conn, String sql, Object[] params):這一方法被用來(lái)執(zhí)行一個(gè)插入、更新或刪除操作。對(duì)象陣列為聲明保存著置換參數(shù)。
現(xiàn)在讓我們來(lái)看一個(gè)例子,在這里你可以從一個(gè)數(shù)據(jù)庫(kù)中獲得一些數(shù)據(jù)。比如說(shuō),我正在使用MySQL 數(shù)據(jù)庫(kù).你還需要下載MYSQL JDBC驅(qū)動(dòng)程序。我正在使用的MySQL數(shù)據(jù)庫(kù)在本地主機(jī),端口號(hào)為3306上運(yùn)行。這個(gè)數(shù)據(jù)庫(kù)地名字叫做test。你將要用到的Student表的結(jié)構(gòu)如下:
Columns Type
------- ----
StudId int
Name varchar
在列表A中,你將會(huì)從Student表中得到一些信息,而且你可以按照你自己的額外需要修改這些信息。盡管你在使用JDBC,但要注意你幾乎沒(méi)寫(xiě)JDBC編碼。(你可能要改變?cè)诶又兴?guī)定的用戶(hù)名和密碼,這是以你的具體的數(shù)據(jù)庫(kù)配置為基礎(chǔ)的。)
這個(gè)編碼遵從以下步驟:
![]() |
![]() |
1.加載JDBC驅(qū)動(dòng)程序類(lèi),并用DriverManager來(lái)得到一個(gè)數(shù)據(jù)庫(kù)連接。
2.例示 QueryRunner 類(lèi)。
3.使用連接、SQL查詢(xún)、參數(shù)和ResultSetHandler來(lái)作為輸入的查詢(xún)方法。你使用一個(gè)類(lèi)org.apache.commons.dbutils.handlers.MapListHandler,一個(gè)類(lèi) MapListHandler來(lái)獲得一個(gè)結(jié)果集(ResultSet)并返回一個(gè)jaca.util.Map的實(shí)例java.util.List。因此結(jié)果集(ResultSet) 的每一行都變成了一個(gè)java.util.Map,所有這些java.util.Map的實(shí)例綁在一起放在一個(gè)java.util.List 中。
4. 反復(fù)得到列表(List)的值就是通過(guò)在列表(List)中獲得每一個(gè)Map的值。
5.用QueryRunner 來(lái)執(zhí)行一個(gè)沒(méi)有參數(shù)的方法。在這里你要用BeanListHandler ,它是一個(gè)非常有用的ResultSetHandler ,因?yàn)槟憧梢园裄esultSet 轉(zhuǎn)變成一個(gè)指定的Bean的列表中。這時(shí)你可以指定一個(gè)Bean類(lèi)到Bean StudentBean中,如同在列表B中所顯示的那樣。
6. 你通過(guò)反復(fù)從列表(List)中得到多個(gè)bean,然后就可從每一個(gè)StudentBean實(shí)例中獲取值。
注釋?zhuān)涸诹斜鞡中,StudentBean 類(lèi)中的StudId 必須是int,這是因?yàn)楸鞸tudent的StudId列的類(lèi)型是int。堅(jiān)持這個(gè)類(lèi)型的匹配是我們需要遵從的唯一規(guī)則。
因?yàn)樵谶@種情況下,StudentBean 類(lèi)的屬性和表Student 的字段是完好的對(duì)映著的,只要將StuentBean 類(lèi)作為一個(gè)參數(shù)就是一個(gè)技巧。字段值用和字段名一樣的名字插入到類(lèi)的屬性中。然而,如果你想要更多地控制bean的創(chuàng)建,則類(lèi)BeanListHandler提供了第二個(gè)構(gòu)造器:BeanListHandler(java.lang.Class type, RowProcessor convert). 接口Rowprocessor的執(zhí)行把結(jié)果集(ResultSet)的各行轉(zhuǎn)化成一個(gè)對(duì)象組。在 StudentBean這一案例中,RowProcessor中的BasicRowProcessor 的執(zhí)行被利用上了,它能夠執(zhí)行這項(xiàng)任務(wù)。然而,你可以寫(xiě)一個(gè)新的執(zhí)行并把它提供給BeanListHandler的構(gòu)造器。
當(dāng)然,執(zhí)行這一編碼的輸出取決于你從表Student中獲得哪些數(shù)據(jù)。對(duì)我來(lái)說(shuō),我得到了以下這些輸出:
***Using MapListHandler***
Id >>1
Name >>One
Id >>2
Name >>Two
***Using BeanListHandler***
Id >>1
Name >>One
Id >>2
Name >>Two
Id >>3
Name >>Three
除了到目前為止你已經(jīng)看了的類(lèi)以外,另外一些你需要研究的類(lèi)是:
- org.apache.commons.dbutils.QueryLoader:QueryLoader是一個(gè)從一個(gè)文件加載查詢(xún)到一個(gè)Map的簡(jiǎn)單的類(lèi)。然后,當(dāng)需要的時(shí)候,你從 Map 中選擇一些查詢(xún)。在沒(méi)有專(zhuān)門(mén)去接觸代碼的情況下,一個(gè)文件中的Having查詢(xún)也可以改變得盡可能的簡(jiǎn)單。
- org.apache.commons.dbutils.wrappers.SqlNullCheckedResultSet:這個(gè)類(lèi)對(duì)使用一個(gè)系統(tǒng)方法來(lái)解決NULL值問(wèn)題是很有用的。用一個(gè) SqINullCheckedResultSet 的實(shí)例來(lái)限制一個(gè)常規(guī)的結(jié)果集(ResultSet) ,然后詳細(xì)地說(shuō)明在遇NULL值的情況下應(yīng)該做些什么。
- org.apache.commons.dbutils.wrappers.StringTrimmedResultSet:用類(lèi)StringTrimmedResultSet 來(lái)約束一個(gè)結(jié)果集,這樣一來(lái),你就可以修整所有g(shù)etString()和getObject()方法返回的字符串。
DbUtils 組件很好也很小巧,很值得在所有用到JDBC的項(xiàng)目中去使用。
DBUtils的JUnit例子:
//使用dbutils1.0版本
import java.util.*;
import java.util.logging.*;
import java.sql.*;
import org.apache.commons.dbutils.*;
import org.apache.commons.dbutils.handlers.*;
public class TestDBUnits {
public static void main(String[]args) throws Exception {
TestDBUnits test = new TestDBUnits();
for(int i = 0 ; i < 1 ; i++) {
test.testQuery1();
test.testQuery2();
test.testUpdate();
}
}
public void testQuery1(){
try {
QueryRunner qr = new QueryRunner() ;
ResultSetHandler rsh = new ArrayListHandler();
String strsql = "select * from test1";
ArrayList result = (ArrayList)qr.query(getConnection() ,strsql ,rsh);
//System.out.print("");
} catch(Exception ex) {
ex.printStackTrace(System.out);
}
}
public void testQuery2(){
try {
QueryRunner qr = new QueryRunner() ;
ResultSetHandler rsh = new MapListHandler();
String strsql = "select * from test1";
ArrayList result = (ArrayList)qr.query(getConnection() ,strsql ,rsh);
for(int i = 0 ; i < result.size() ; i++) {
Map map = (Map)result.get(i);
//System.out.println(map);
}
//System.out.print("");
} catch(Exception ex) {
ex.printStackTrace(System.out);
}
}
public void testUpdate(){
try {
QueryRunner qr = new QueryRunner() ;
ResultSetHandler rsh = new ArrayListHandler();
String strsql = "insert test1(page ,writable ,content)values('ttt','ttt','faskldfjklasdjklfjasdklj')";
qr.update(getConnection() ,strsql);
//System.out.print("");
} catch(Exception ex) {
ex.printStackTrace(System.out);
}
}
private Connection getConnection() throws InstantiationException,
IllegalAccessException, ClassNotFoundException, SQLException {
String strDriver = "org.gjt.mm.mysql.Driver";
String strUrl = "jdbc:mysql://localhost:3306/test";
String strUser = "root";
String strPass = "";
Class.forName(strDriver).newInstance();
return DriverManager.getConnection(strUrl, strUser, strPass);
}
}
posted on 2005-11-30 10:18 Victor 閱讀(1271) 評(píng)論(0) 編輯 收藏 所屬分類(lèi): 開(kāi)源相關(guān)