作者: Builder.comMonday, April 26 2004 4:43 PM
JDBC碼是Java譯碼的一個部分,它給已寫的編碼帶來了數量驚人的重復。另外,JDBC碼幾乎會經常性的帶來一些低級錯誤。寫出好的JDBC編碼并不難,但是很痛苦。
DbUtils組件是一個精密而簡單的組件,它并不做什么復雜的事而僅僅只是使很多的JDBC任務對開發者來說變得稍容易一點。盡管這時候很多持久框架和包都可以用來使數據持久變得更容易,然而JDBC仍然是大多數Java和Java2企業版(J2EE)開發者賴以生存的工具。因此,任何能讓使用JDBC工作更容易的東西都是好消息。
DbUtils可以免費下載
,它不依賴于任何其它的通用組件而只是依賴下面這些:
- Java Development Kit (JDK) 1.2 (or later)
- JDBC 2.0 (or later)
DbUtils文檔并不是最好的,但是足以使你的工作正常進行。在下一節,你會看到DbUtils中最有用的類以及一些關于它們的用法的例子。你應該能夠很容易地使用這些編碼和例子,然后能夠馬上在你自己的項目中開始使用DbUtils。我將會集中精力于兩個類(org.apache.commons.dbutils.DbUtils 和org.apache.commons.dbutils.QueryRunner)和一個接口(org.apache.commons.dbutils.ResultSethandler).在我給你們一些關于它們的用法的例子之前,讓我們深入DbUtils里面來仔細看看它給我們提供了些什么。
DbUtils
DbUtils是一個為做一些諸如關閉連接、裝載JDBC驅動程序之類的常規工作提供有用方法的類,它里面所有的方法都是靜態的。
這個類里的重要方法有:
- close:DbUtils類提供了三個重載的關閉方法。這些方法檢查所提供的參數是不是NULL,如果不是的話,它們就關閉連接、聲明和結果集(ResultSet)。
- CloseQuietly: CloseQuietly這一方法不僅能在連接、聲明或者結果集(ResultSet)為NULL情況下避免關閉,還能隱藏一些在程序中拋出的SQLEeception。如果你不想捕捉這些異常的話,這對你是非常有用的。在重載CloseQuietly方法時,特別有用的一個方法是closeQuietly(Connection conn,Statement stmt,ResultSet rs),這是因為在大多數情況下,連接、聲明和結果集(ResultSet)是你要用的三樣東西,而且在最后的塊你必須關閉它們。使用這一方法,你最后的塊就可以只需要調用這一方法即可。
- CommitAndCloseQuietly(Connection conn):這一方法用來提交連接,然后關閉連接,并且在關閉連接時不向上拋出在關閉時發生的一些SQL異常。
- LoadDriver(String driveClassName): 這一方法裝載并注冊JDBC驅動程序,如果成功就返回TRUE。使用這種方法,你不需要去捕捉這個異常ClassNotFoundException。使用loadDrive方法,編碼就變得更容易理解,你也就得到了一個很好的Boolean返回值,這個返回值會告訴你驅動類是不是已經加載成功了。
ResultSetHandler
正如它的名字所提示的,這一接口執行處理一個jaca.sql.ResultSet,將數據轉變并處理為任何一種形式,這樣有益于其應用而且使用起來更容易。這一組件提供了ArrayHandler, ArrayListHandler, BeanHandler, BeanListHandler, MapHandler, MapListHandler, and ScalarHandler等執行程序。
ResultSetHandler接口提供了一個單獨的方法:Object handle (java.sql.ResultSet .rs)。因此任何ResultSetHandler 的執行需要一個結果集(ResultSet)作為參數傳入,然后才能處理這個結果集,再返回一個對象。因為返回類型是java.lang.Object,所以除了不能返回一個原始的Java類型之外,其它的返回類型并沒有什么限制。如果你發現這七個執行程序中沒有任何一個提供了你想要的服務,你可以自己寫執行程序并使用它。
QreryRunner
這個類使執行SQL查詢簡單化了,它與ResultSetHandler串聯在一起有效地履行著一些平常的任務,它能夠大大減少你所要寫的編碼。QueryRunner類提供了兩個構造器:其中一個是一個空構造器,另一個則拿一個 javax.sql.DataSource 來作為參數。因此,在你不用為一個方法提供一個數據庫連接來作為參數的情況下,提供給構造器的數據源(DataSource) 被用來獲得一個新的連接并將繼續進行下去。
這一類中的重要方法包括以下這些:
- query(Connection conn, String sql, Object[] params, ResultSetHandler rsh):這一方法執行一個選擇查詢,在這個查詢中,對象陣列的值被用來作為查詢的置換參數。這一方法內在地處理PreparedStatement 和ResultSet 的創建和關閉。ResultSetHandler對把從 ResultSet得來的數據轉變成一個更容易的或是應用程序特定的格式來使用。
- query(String sql, Object[] params, ResultSetHandler rsh):這幾乎與第一種方法一樣;唯一的不同在于它不將數據庫連接提供給方法,并且它是從提供給構造器的數據源(DataSource) 或使用的setDAtaSource 方法中重新獲得的。
- query(Connection conn, String sql, ResultSetHandler rsh):這執行一個不要參數的選擇查詢。
- update(Connection conn, String sql, Object[] params):這一方法被用來執行一個插入、更新或刪除操作。對象陣列為聲明保存著置換參數。
現在讓我們來看一個例子,在這里你可以從一個數據庫中獲得一些數據。比如說,我正在使用MySQL 數據庫.你還需要下載MYSQL JDBC驅動程序。我正在使用的MySQL數據庫在本地主機,端口號為3306上運行。這個數據庫地名字叫做test。你將要用到的Student表的結構如下:
Columns Type
------- ----
StudId int
Name varchar
在列表A中,你將會從Student表中得到一些信息,而且你可以按照你自己的額外需要修改這些信息。盡管你在使用JDBC,但要注意你幾乎沒寫JDBC編碼。(你可能要改變在例子中所規定的用戶名和密碼,這是以你的具體的數據庫配置為基礎的。)
這個編碼遵從以下步驟:
1.加載JDBC驅動程序類,并用DriverManager來得到一個數據庫連接。
2.例示 QueryRunner 類。
3.使用連接、SQL查詢、參數和ResultSetHandler來作為輸入的查詢方法。你使用一個類org.apache.commons.dbutils.handlers.MapListHandler,一個類 MapListHandler來獲得一個結果集(ResultSet)并返回一個jaca.util.Map的實例java.util.List。因此結果集(ResultSet) 的每一行都變成了一個java.util.Map,所有這些java.util.Map的實例綁在一起放在一個java.util.List 中。
4. 反復得到列表(List)的值就是通過在列表(List)中獲得每一個Map的值。
5.用QueryRunner 來執行一個沒有參數的方法。在這里你要用BeanListHandler ,它是一個非常有用的ResultSetHandler ,因為你可以把ResultSet 轉變成一個指定的Bean的列表中。這時你可以指定一個Bean類到Bean StudentBean中,如同在列表B中所顯示的那樣。
6. 你通過反復從列表(List)中得到多個bean,然后就可從每一個StudentBean實例中獲取值。
注釋:在列表B中,StudentBean 類中的StudId 必須是int,這是因為表Student的StudId列的類型是int。堅持這個類型的匹配是我們需要遵從的唯一規則。
因為在這種情況下,StudentBean 類的屬性和表Student 的字段是完好的對映著的,只要將StuentBean 類作為一個參數就是一個技巧。字段值用和字段名一樣的名字插入到類的屬性中。然而,如果你想要更多地控制bean的創建,則類BeanListHandler提供了第二個構造器:BeanListHandler(java.lang.Class type, RowProcessor convert). 接口Rowprocessor的執行把結果集(ResultSet)的各行轉化成一個對象組。在 StudentBean這一案例中,RowProcessor中的BasicRowProcessor 的執行被利用上了,它能夠執行這項任務。然而,你可以寫一個新的執行并把它提供給BeanListHandler的構造器。
當然,執行這一編碼的輸出取決于你從表Student中獲得哪些數據。對我來說,我得到了以下這些輸出:
***Using MapListHandler***
Id >>1
Name >>One
Id >>2
Name >>Two
***Using BeanListHandler***
Id >>1
Name >>One
Id >>2
Name >>Two
Id >>3
Name >>Three
除了到目前為止你已經看了的類以外,另外一些你需要研究的類是:
- org.apache.commons.dbutils.QueryLoader:QueryLoader是一個從一個文件加載查詢到一個Map的簡單的類。然后,當需要的時候,你從 Map 中選擇一些查詢。在沒有專門去接觸代碼的情況下,一個文件中的Having查詢也可以改變得盡可能的簡單。
- org.apache.commons.dbutils.wrappers.SqlNullCheckedResultSet:這個類對使用一個系統方法來解決NULL值問題是很有用的。用一個 SqINullCheckedResultSet 的實例來限制一個常規的結果集(ResultSet) ,然后詳細地說明在遇NULL值的情況下應該做些什么。
- org.apache.commons.dbutils.wrappers.StringTrimmedResultSet:用類StringTrimmedResultSet 來約束一個結果集,這樣一來,你就可以修整所有getString()和getObject()方法返回的字符串。
DbUtils 組件很好也很小巧,很值得在所有用到JDBC的項目中去使用。
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);
}
}