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

    這些作用是通過一系列API實(shí)現(xiàn)的,其中的幾個(gè)重要接口如表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ū)動程序登錄時(shí)間 限制及登錄和跟蹤消息的顯示等事務(wù)。DriverManager 類直接繼承自java.lang.object,其主要成員方法如表13-2所示。 

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

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

    Connection

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

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


    Statement

    Statement 用于在已經(jīng)建立的連接的基礎(chǔ)上向數(shù)據(jù)庫發(fā)送SQL語句的對象。它只是一個(gè)接口的定義,其中包括了執(zhí)行SQL語句和獲取返回結(jié)果的方法。實(shí)際上有3種 Statement 對象:Statement、PreparedStatement(繼承自Statement )和 CallableStatement(繼承自PreparedStatement)。它們都作為在給定連接上執(zhí)行 SQL 語句的容器,每個(gè)都專用于發(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í)行多個(gè)SQL語句
ResultSet executeQuery(String sql)    進(jìn)行數(shù)據(jù)庫查詢,返回結(jié)果集
int executeUpdate(String sql)    進(jìn)行數(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的下一個(gè)結(jié)果
int getQueryTimeout()     獲取查詢超時(shí)設(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è)置查詢超時(shí)時(shí)間

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

    PreparedStatement接口繼承了Statement接口, 但PreparedStatement語句中包含了經(jīng)過預(yù)編譯的SQL語句,因此可以獲得更高的執(zhí)行效率。在PreparedStatement語句中可 以包含多個(gè)用"?"代表的字段,在程序中可以利用setXXX方法設(shè)置該字段的內(nèi)容,從而增強(qiáng)了程序設(shè)計(jì)的動態(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()    進(jìn)行數(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è)置為十進(jìn)制長類型
void setBinaryStream
(int index,InputStream stream,int length)    設(shè)置為二進(jìn)制輸入流
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è)置為浮點(diǎn)類型
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è)置為時(shí)間類型


    PreparedStatement 與Statement的區(qū)別在于它構(gòu)造的SQL語句不是完整的語句,而需要在程序中進(jìn)行動態(tài)設(shè)置。這一方面增強(qiáng)了程序設(shè)計(jì)的靈活性;另一方面,由于 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 = ?");

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

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

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

 

如果我們想給前50個(gè)注冊的用戶每人5000點(diǎn)獎勵,則可以用循環(huán)語句對空字段進(jì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 輸入流來完成。當(dāng)語句執(zhí)行時(shí),JDBC驅(qū)動程序?qū)⒅貜?fù)調(diào)用該輸入流,讀取其內(nèi)容并將它們當(dāng)做實(shí)際參數(shù)數(shù)據(jù)傳輸。JDBC 提供了3種將IN參數(shù)設(shè)置為輸入流的方法:setBinaryStream用于含有未說明字節(jié)的流;setAsciiStream用于含有ASCII字符 的流;setUnicodeStream用于含有Unicode字符的流。這些方法比其他的setXXX方法要多一個(gè)用于指定流的總長度的參數(shù),因?yàn)橐恍? 數(shù)據(jù)庫在發(fā)送數(shù)據(jù)之前需要知道它傳送的數(shù)據(jù)的大小。



    下面是一個(gè)使用流作為 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();


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

    CallableStatement 對象用于執(zhí)行對數(shù)據(jù)庫已存儲過程的調(diào)用。在CallableStatement對象中,有一個(gè)通用的成員方法call,這個(gè)方法用于以名稱的方式調(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)    獲取十進(jìn)制小數(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)     獲取日期類型浮點(diǎn)類型
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)     獲取時(shí)間類型
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[(?,?,?,)]} // 過程需要若干個(gè)參數(shù)

{? = call procedure_name[(?,?,?,)]} //過程需要若干個(gè)參數(shù)并返回一個(gè)參數(shù)

 

 

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

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

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

如果需要存儲過程返回運(yùn)行結(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í)存放數(shù)據(jù)庫查詢操作獲得的結(jié)果。它包含了符合 SQL 語句中條件的所有行,并且它提供了一套 get 方法對這些行中的數(shù)據(jù)進(jìn)行訪問。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é)果集中的某一行并將其存入一個(gè)數(shù)組
boolean getBoolean(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)布爾型值
byte getByte(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)字節(jié)型值
short getShort(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)短整型值
int getInt(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)整型值
long getLong(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)長整型值
double getDouble(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)雙精度型值
float getFloat(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)浮點(diǎn)型值
String getString(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)字符串
Date getDate(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)日期型值
Object getObject(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)對象
Statement getStatement()    獲得產(chǎn)生該結(jié)果集的Statement對象
URL getURL(int columnIndex)    獲取當(dāng)前行中某一列的值,返回一個(gè)java.net.URL型值
boolean isBeforeFirst()    判斷指針是否在結(jié)果集的頭部
boolean isAfterLast()    判斷指針是否在結(jié)果集的末尾
boolean isFirst()    判斷指針是否在結(jié)果集的第一行
boolean isLast()    判斷指針是否在結(jié)果集的最后一行
boolean last()    將指針移動到結(jié)果集的最后一行
boolean next()    將指針移動到當(dāng)前行的下一行
boolean previous()    將指針移動到當(dāng)前行的前一行

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