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

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

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

 這些JDBC API的組成結構如圖13-2所示。


圖13-2 JDBC API的組成結構



     DriverManager

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

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

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

    Connection

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

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


    Statement

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

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

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

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

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

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

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


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

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

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

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

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

 

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

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

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



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

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í)行時,將反復調用輸入流 fin 以傳遞其數據。

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

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

表13-6 CallableStatement 接口的主要成員方法及其含義
方 法     含 義
Array getArray(int I)    獲取數組
BigDecimal getBigDecimal(int index)
BigDecimal getBigDecimal(int index,int scale)    獲取十進制小數
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)     獲取日期類型整數類型
long getLong(int index)     獲取日期類型長整數類型
Object getObject(int index)
Object getObject(int index,Map map)     獲取對象類型
Ref getRef(int I)      獲取日期類型Ref類型
short getShort(int index)     獲取日期類型短整數類型
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) 注冊輸出參數
&nbsp;&nbsp;&nbsp;&nbsp;調用存儲過程的語法為:
{call procedure_name} // 過程不需要參數

{call procedure_name[(?,?,?,)]} // 過程需要若干個參數

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

 

 

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

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

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

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

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的基本數據類型和SQL中支持的數據類型有一定的對應關系。這種對應關系如表13-7所示。

表13-7 SQL的數據類型與Java數據類型的對應關系
SQL數據類型     Java數據類型
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

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

表13-8 ResultSet類的主要成員方法及其含義
方 法     含 義
boolean absolute(int row)    將指針移動到結果集對象的某一行
void afterLast()    將指針移動到結果集對象的末尾
void beforeFirst()    將指針移動到結果集對象的頭部
boolean first()    將指針移動到結果集對象的第一行
Array getArray(int row)    獲取結果集中的某一行并將其存入一個數組
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()    獲得產生該結果集的Statement對象
URL getURL(int columnIndex)    獲取當前行中某一列的值,返回一個java.net.URL型值
boolean isBeforeFirst()    判斷指針是否在結果集的頭部
boolean isAfterLast()    判斷指針是否在結果集的末尾
boolean isFirst()    判斷指針是否在結果集的第一行
boolean isLast()    判斷指針是否在結果集的最后一行
boolean last()    將指針移動到結果集的最后一行
boolean next()    將指針移動到當前行的下一行
boolean previous()    將指針移動到當前行的前一行

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