JDBC的作用及重要接口

2010-08-28 10:45:15來源:西部e網(wǎng)作者:

    JDBC是由一系列連接(Connection)、SQL語句(Statement)和結(jié)果集(ResultSet)構(gòu)成的,其主要作用概括起來有如下3個方面:
    建立與數(shù)據(jù)庫的連接。
    向數(shù)據(jù)庫發(fā)起查詢請求。
    處理數(shù)據(jù)庫返回結(jié)果。

    這些作用是通過一系列API實現(xiàn)的,其中的幾個重要接口如表13-1所示。

表13-1  JDBC API中的重要接口
接    口	                   作    用
java.sql.DriverManager	處理驅(qū)動程序的加載和建立新數(shù)據(jù)庫連接
java.sql.Connection 	處理與特定數(shù)據(jù)庫的連接
java.sql.Statement	    在指定連接中處理SQL語句
java.sql.ResultSet	    處理數(shù)據(jù)庫操作結(jié)果集


    這些JDBC API的組成結(jié)構(gòu)如圖13-2所示。


圖13-2 JDBC API的組成結(jié)構(gòu)


     DriverManager

    DriverManager類是Java.sql包中用于數(shù)據(jù)庫驅(qū)動程序管理的類,作用于用戶和驅(qū)動程序之間。它跟蹤可用的驅(qū)動程序,并在數(shù)據(jù)庫和相應(yīng)驅(qū)動程序之間建立連接,也處理諸如驅(qū)動程序登錄時間限制及登錄和跟蹤消息的顯示等事務(wù)。DriverManager 類直接繼承自java.lang.object,其主要成員方法如表13-2所示。

表13-2 DriverManager的主要成員方法及其含義


    對于簡單的應(yīng)用程序,程序開發(fā)人員需要在此類中直接使用的惟一方法是 DriverManager.getConnection。該方法是用來建立與數(shù)據(jù)庫的連接的。JDBC 允許用戶調(diào)用 DriverManager 的方法 getDriver、getDrivers 和 registerDriver 及 Driver 的方法 connect。但多數(shù)情況下,最好讓 DriverManager 類管理建立連接的細節(jié)。

    Connection

    Connection是用來表示數(shù)據(jù)庫連接的對象,對數(shù)據(jù)庫的一切操作都是在這個連接的基礎(chǔ)上進行的。Connection類的主要成員方法如表13-3所示。

表13-3  Connection類的主要成員方法及其含義
方    法	             含    義
void clearWarnings	清除連接的所有警告信息
Statement createStatement()	創(chuàng)建一個statement對象
Statement createStatement(int resultSetType, int resultSetConcurrency)
創(chuàng)建一個statement對象,它將生成具有特定類型和并發(fā)性的結(jié)果集
void commit()	   提交對數(shù)據(jù)庫的改動并釋放當前連接持有的數(shù)據(jù)庫的鎖
void rollback()	   回滾當前事務(wù)中的所有改動并釋放當前連接持有的數(shù)據(jù)庫的鎖
String getCatalog()	獲取連接對象的當前目錄名
boolean isClosed()	判斷連接是否已關(guān)閉
boolean isReadOnly()	判斷連接是否為只讀模式
void setReadOnly()	設(shè)置連接的只讀模式
void close()	立即釋放連接對象的數(shù)據(jù)庫和JDBC資源


    Statement

    Statement用于在已經(jīng)建立的連接的基礎(chǔ)上向數(shù)據(jù)庫發(fā)送SQL語句的對象。它只是一個接口的定義,其中包括了執(zhí)行SQL語句和獲取返回結(jié)果的方法。實際上有3種 Statement 對象:Statement、PreparedStatement(繼承自Statement )和 CallableStatement(繼承自PreparedStatement)。它們都作為在給定連接上執(zhí)行 SQL 語句的容器,每個都專用于發(fā)送特定類型的 SQL 語句: Statement 對象用于執(zhí)行不帶參數(shù)的簡單 SQL 語句;PreparedStatement 對象用于執(zhí)行帶或不帶 IN 參數(shù)的預(yù)編譯 SQL 語句;CallableStatement 對象用于執(zhí)行對數(shù)據(jù)庫已存儲過程的調(diào)用。Statement 接口提供了執(zhí)行語句和獲取結(jié)果的基本方法;PreparedStatement 接口添加了處理 IN 參數(shù)的方法;而 CallableStatement 添加了處理 OUT 參數(shù)的方法。

    創(chuàng)建statement對象的方法如下:
    Statement stmt = con.createStatement();

    Statement接口定義中包括的方法如表13-4所示。

表13-4  Statement接口的主要成員方法及其含義
方    法	                     含    義
void addBatch(String sql)	在Statement語句中增加用于數(shù)據(jù)庫操作的SQL批處理語句
void cancel()	            取消Statement中的SQL語句指定的數(shù)據(jù)庫操作命令
void clearBatch()	        清除Statement中的SQL批處理語句
void clearWarnings()	    清除Statement語句中的操作引起的警告
void close()	            關(guān)閉Statement語句指定的數(shù)據(jù)庫連接
boolean execute(String sql)	執(zhí)行SQL語句
int[] executeBatch()	     執(zhí)行多個SQL語句
ResultSet executeQuery(String sql)	進行數(shù)據(jù)庫查詢,返回結(jié)果集
int executeUpdate(String sql)	進行數(shù)據(jù)庫更新
Connection getConnection()	 獲取對數(shù)據(jù)庫的連接
int getFetchDirection()	     獲取從數(shù)據(jù)庫表中獲取行數(shù)據(jù)的方向
int getFetchSize()	         獲取返回的數(shù)據(jù)庫結(jié)果集行數(shù)
int getMaxFieldSize()	     獲取返回的數(shù)據(jù)庫結(jié)果集最大字段數(shù)
int getMaxRows()	         獲取返回的數(shù)據(jù)庫結(jié)果集最大行數(shù)
boolean getMoreResults()	獲取Statement的下一個結(jié)果
int getQueryTimeout()	    獲取查詢超時設(shè)置
ResultSet getResultSet()	獲取結(jié)果集
int getUpdateCount()	    獲取更新記錄的數(shù)量
void setCursorName(String name)	設(shè)置數(shù)據(jù)庫Cursor的名稱
void setFetchDirection(int dir)	設(shè)置數(shù)據(jù)庫表中獲取行數(shù)據(jù)的方向
void setFetchSize(int rows)	    設(shè)置返回的數(shù)據(jù)庫結(jié)果集行數(shù)
void setMaxFieldSize(int max)	設(shè)置最大字段數(shù)
void setMaxRows(int max)	     設(shè)置最大行數(shù)
void setQueryTimeout(int seconds)設(shè)置查詢超時時間


    值得注意的是,Statement 接口提供了3種執(zhí)行SQL語句的方法:executeQuery、executeUpdate和execute。使用哪一個方法由SQL語句所產(chǎn)生的內(nèi)容決定。executeQuery方法用于產(chǎn)生單個結(jié)果集的SQL語句,如SELECT語句。executeUpdate方法用于執(zhí)行INSERT、UPDATE、DELETE及DDL(數(shù)據(jù)定義語言)語句,例如CREATE TABLE 和 DROP TABLE。executeUpdate 的返回值是一個整數(shù),表示它執(zhí)行的SQL語句所影響的數(shù)據(jù)庫中的表的行數(shù)(更新計數(shù))。execute 方法用于執(zhí)行返回多個結(jié)果集或多個更新計數(shù)的語句。

    PreparedStatement接口繼承了Statement接口,但PreparedStatement語句中包含了經(jīng)過預(yù)編譯的SQL語句,因此可以獲得更高的執(zhí)行效率。在PreparedStatement語句中可以包含多個用"?"代表的字段,在程序中可以利用setXXX方法設(shè)置該字段的內(nèi)容,從而增強了程序設(shè)計的動態(tài)性。PreparedStatement接口的主要成員方法及其含義如表13-5所示。

表13-5  PreparedStatement接口的主要成員方法及其含義
方    法	                    含    義
void addBatch(String sql)	在Statement語句中增加用于數(shù)據(jù)庫操作的SQL批處理語句
void clearparameters ()	     清除PreparedStatement中的設(shè)置參數(shù)
ResultSet executeQuery(String sql)	執(zhí)行SQL查詢語句
ResultSetMetaData getMetaData()	進行數(shù)據(jù)庫查詢,獲取數(shù)據(jù)庫元數(shù)據(jù)
void setArray(int index,Array x)	設(shè)置為數(shù)組類型
void setAsciiStream(int index,InputStream stream,int length)設(shè)置為ASCII輸入流
void setBigDecimal(int index,BigDecimal x)	設(shè)置為十進制長類型
void setBinaryStream
(int index,InputStream stream,int length)	設(shè)置為二進制輸入流
void setCharacterStream
(int index,InputStream stream,int length)	設(shè)置為字符輸入流
void setBoolean(int index, boolean x)	設(shè)置為邏輯類型
void setByte(int index,byte b)	設(shè)置為字節(jié)類型
void setBytes(int byte[] b)	設(shè)置為字節(jié)數(shù)組類型
void setDate(int index,Date x)	設(shè)置為日期類型
void setFloat(int index,float x)	設(shè)置為浮點類型
void setInt(int index,int x)	設(shè)置為整數(shù)類型
void setLong(int index,long x)	設(shè)置為長整數(shù)類型
void setRef(int index,int ref)	設(shè)置為引用類型
void setShort(int index,short x)	設(shè)置為短整數(shù)類型
void setString(int index,String x)	設(shè)置為字符串類型
void setTime(int index,Time x)	設(shè)置為時間類型


    PreparedStatement與Statement的區(qū)別在于它構(gòu)造的SQL語句不是完整的語句,而需要在程序中進行動態(tài)設(shè)置。這一方面增強了程序設(shè)計的靈活性;另一方面,由于PreparedStatement語句是經(jīng)過預(yù)編譯的,因此它構(gòu)造的SQL語句的執(zhí)行效率比較高。所以對于某些使用頻繁的SQL語句,用PreparedStatement語句比用Statement具有明顯的優(yōu)勢。

    PreparedStatement對象的創(chuàng)建方法如下:
    PreparedStatement pstmt = con.prepareStatement("update tbl_User set reward = ? where userId = ?");

    在該語句中,包括兩個可以進行動態(tài)設(shè)置的字段:reward和userId。

    例如,我們想給第一個注冊的用戶5000點獎勵,則可以用下面的方法設(shè)置空字段的內(nèi)容:

pstmt.setInt(1, 5000);
pstmt. setInt (2, 1);


    如果我們想給前50個注冊的用戶每人5000點獎勵,則可以用循環(huán)語句對空字段進行設(shè)置:

pstmt.setInt(1, 5000);
for (int i = 0; i < 50; i++)
{
   pstmt.setInt(2,i);
   int rowCount = pstmt.executeUpdate();
}


    如果傳遞的數(shù)據(jù)量很大,則可以通過將 IN 參數(shù)設(shè)置為 Java 輸入流來完成。當語句執(zhí)行時,JDBC驅(qū)動程序?qū)⒅貜驼{(diào)用該輸入流,讀取其內(nèi)容并將它們當做實際參數(shù)數(shù)據(jù)傳輸。JDBC 提供了3種將IN參數(shù)設(shè)置為輸入流的方法:setBinaryStream用于含有未說明字節(jié)的流;setAsciiStream用于含有ASCII字符的流;setUnicodeStream用于含有Unicode字符的流。這些方法比其他的setXXX方法要多一個用于指定流的總長度的參數(shù),因為一些數(shù)據(jù)庫在發(fā)送數(shù)據(jù)之前需要知道它傳送的數(shù)據(jù)的大小。

    下面是一個使用流作為 IN 參數(shù)發(fā)送文件內(nèi)容的例子:

java.io.File file = new java.io.File("/tmp/data");
int fileLength = file.length();
java.io.InputStream fin = new java.io.FileInputStream(file);
java.sql.PreparedStatement pstmt = con.prepareStatement(
"update table set stuff = ? where index = 4");
pstmt.setBinaryStream (1, fin, fileLength);
pstmt.executeUpdate();


    當語句執(zhí)行時,將反復調(diào)用輸入流 fin 以傳遞其數(shù)據(jù)。

    CallableStatement 對象用于執(zhí)行對數(shù)據(jù)庫已存儲過程的調(diào)用。在CallableStatement對象中,有一個通用的成員方法call,這個方法用于以名稱的方式調(diào)用數(shù)據(jù)庫中的存儲過程。在數(shù)據(jù)庫調(diào)用過程中,可以通過設(shè)置IN參數(shù)向調(diào)用的存儲過程提供執(zhí)行所需的參數(shù)。另外,在存儲過程的調(diào)用中,通過OUT參數(shù)獲取存儲過程的執(zhí)行結(jié)果。

    CallableStatement 接口的主要成員方法及其含義如表13-6所示。

表13-6  CallableStatement 接口的主要成員方法及其含義
方    法	              含    義
Array getArray(int I)	獲取數(shù)組
BigDecimal getBigDecimal(int index) 
BigDecimal getBigDecimal(int index,int scale)	獲取十進制小數(shù)
boolean getBoolean(int index)	獲取邏輯類型
byte getByte(int index)	獲取字節(jié)類型
Date getDate(int index)Date getDate
(int index,Calendar cal)	獲取日期類型
double getDouble(int index)  	獲取日期類型雙精度類型
float getFloat(int index)  	獲取日期類型浮點類型
int getint(int index)  	獲取日期類型整數(shù)類型
long getLong(int index)  	獲取日期類型長整數(shù)類型
Object getObject(int index) 
Object getObject(int index,Map map)  	獲取對象類型
Ref getRef(int I)  	         獲取日期類型Ref類型
short getShort(int index)  	獲取日期類型短整數(shù)類型
String getString(int index) 	獲取日期類型字符串類型
Time getTime(int index) Time 
getTime(int index,Calendar cal)  	獲取時間類型
void registerOutputParameter(int index)
void registerOutputParameter(int index,int type)
void registerOutputParameter
(int index,int type,int scale)   注冊輸出參數(shù)
&nbsp;&nbsp;&nbsp;&nbsp;調(diào)用存儲過程的語法為:
{call procedure_name}              // 過程不需要參數(shù)
{call procedure_name[(?,?,?,…)]}    // 過程需要若干個參數(shù)
{? = call procedure_name[(?,?,?,…)]} //過程需要若干個參數(shù)并返回一個參數(shù)


    其中procedure_name為存儲過程的名字,方括號中的內(nèi)容是可選的多個用于存儲過程執(zhí)行的參數(shù)。CallableStatement 對象的創(chuàng)建方法如下:
    CallableStatement cstmt = con.prepareCall("{call getData(?, ?)}");

    向存儲過程傳遞執(zhí)行需要參數(shù)的方法是通過setXXX語句完成的。例如,我們可以將兩個參數(shù)設(shè)置如下:

cstmt.setByte(1, 25);
cstmt.setInt(2,64.85);


    如果需要存儲過程返回運行結(jié)果,則需要調(diào)用registerOutParameter方法設(shè)置存儲過程的輸出參數(shù),然后調(diào)用getXXX方法來獲取存儲過程的執(zhí)行結(jié)果。例如:

cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.registerOutParameter(1, java.sql.Types. INTEGER);
cstmt.executeUpdate();
byte a = cstmt.getByte(1);
int b = cstmt.getInt(2);


    從上面的程序可以看出,Java的基本數(shù)據(jù)類型和SQL中支持的數(shù)據(jù)類型有一定的對應(yīng)關(guān)系。這種對應(yīng)關(guān)系如表13-7所示。

表13-7  SQL的數(shù)據(jù)類型與Java數(shù)據(jù)類型的對應(yīng)關(guān)系
SQL數(shù)據(jù)類型	 Java數(shù)據(jù)類型
CHAR 	    String 
VARCHAR 	String 
LONGVARCHAR String 
NUMERIC 	java.math.BigDecimal 
DECIMAL 	java.math.BigDecimal 
BIT 	    boolean 
TINYINT 	byte 
SMALLINT 	short 
INTEGER 	int 
BIGINT 	    long 
REAL 	   float 
FLOAT 	   double 
DOUBLE 	   double 
BINARY   	byte[] 
VARBINARY 	byte[] 
LONGVARBINARY 	byte[] 
DATE 	java.sql.Date 
TIME 	java.sql.Time 
TIMESTAMP 	java.sql.Timestamp


    ResultSet

    結(jié)果集(ResultSet)用來暫時存放數(shù)據(jù)庫查詢操作獲得的結(jié)果。它包含了符合 SQL 語句中條件的所有行,并且它提供了一套 get 方法對這些行中的數(shù)據(jù)進行訪問。ResultSet類的主要成員方法及其含義如表13-8所示。

表13-8  ResultSet類的主要成員方法及其含義
方    法	                    含    義
boolean absolute(int row)	將指針移動到結(jié)果集對象的某一行
void afterLast()	將指針移動到結(jié)果集對象的末尾
void beforeFirst()	將指針移動到結(jié)果集對象的頭部
boolean first()	將指針移動到結(jié)果集對象的第一行
Array getArray(int row)	獲取結(jié)果集中的某一行并將其存入一個數(shù)組
boolean getBoolean(int columnIndex)	獲取當前行中某一列的值,返回一個布爾型值
byte getByte(int columnIndex)	獲取當前行中某一列的值,返回一個字節(jié)型值
short getShort(int columnIndex)	獲取當前行中某一列的值,返回一個短整型值
int getInt(int columnIndex)	獲取當前行中某一列的值,返回一個整型值
long getLong(int columnIndex)	獲取當前行中某一列的值,返回一個長整型值
double getDouble(int columnIndex)	獲取當前行中某一列的值,返回一個雙精度型值
float getFloat(int columnIndex)	獲取當前行中某一列的值,返回一個浮點型值
String getString(int columnIndex)	獲取當前行中某一列的值,返回一個字符串
Date getDate(int columnIndex)	獲取當前行中某一列的值,返回一個日期型值
Object getObject(int columnIndex)	獲取當前行中某一列的值,返回一個對象
Statement getStatement()	獲得產(chǎn)生該結(jié)果集的Statement對象
URL getURL(int columnIndex)	獲取當前行中某一列的值,返回一個java.net.URL型值
boolean isBeforeFirst()	判斷指針是否在結(jié)果集的頭部
boolean isAfterLast()	判斷指針是否在結(jié)果集的末尾
boolean isFirst()	判斷指針是否在結(jié)果集的第一行
boolean isLast()	判斷指針是否在結(jié)果集的最后一行
boolean last()	將指針移動到結(jié)果集的最后一行
boolean next()	將指針移動到當前行的下一行
boolean previous()	將指針移動到當前行的前一行


    從表13-8中可以看出,ResultSet類不僅提供了一套用于訪問數(shù)據(jù)的get方法,還提供了很多移動指針(cursor,有時也譯為光標)的方法。cursor是ResultSet 維護的指向當前數(shù)據(jù)行的指針。最初它位于第一行之前,因此第一次訪問結(jié)果集時通常調(diào)用 next方法將指針置于第一行上,使它成為當前行。隨后每次調(diào)用 next 指針向下移動一行。
關(guān)鍵詞:JDBC連接SQL