JDBCTM 指南:入門7 - CallableStatement (轉)

worldblog發表於2007-12-08
JDBCTM 指南:入門7 - CallableStatement (轉)[@more@]7 - CallableStatement
本概述是從《JCTM Database Access from TM: A Tutorial and Annotated Reference 》這本書中摘引來的。JavaSoft 目前正在準備這本書。這本書是一本教程,同時也是 的重要參考手冊,它將作為 Java 系列的組成部份在 1997 年春季由 Addison-Wesley 出版公司出版。


7.1 概述
CallableStatement 為所有的 DBMS 提供了一種以標準形式已儲存過程的方法。已儲存過程儲存在中。對已儲存過程的呼叫是 CallableStatement 物件所含的內容。這種呼叫是用一種換碼語法來寫的,有兩種形式:一種形式帶結果引數,另一種形式不帶結果引數(有關換碼語法的資訊,參見第 4 節“語句”)。結果引數是一種輸出 (OUT) 引數,是已儲存過程的返回值。兩種形式都可帶有數量可變的輸入(IN 引數)、輸出(OUT 引數)或輸入和輸出(INOUT 引數)的引數。問號將用作引數的佔位符。

在 JDBC 中呼叫已儲存過程的語法如下所示。注意,方括號表示其間的內容是可選項;方括號本身並不是語法的組成部份。

{call 過程名[(?, ?, ...)]}

返回結果引數的過程的語法為:

{? = call 過程名[(?, ?, ...)]}

不帶引數的已儲存過程的語法類似:

{call 過程名}

通常,建立 CallableStatement 物件的人應當知道所用的 DBMS 是支援已儲存過程的,並且知道這些過程都是些什麼。然而,如果需要檢查,多種 DatabaseMetaData 方法都可以提供這樣的資訊。例如,如果 DBMS 支援已儲存過程的呼叫,則 supportsStoredProcedures 方法將返回 true,而 getProcedures 方法將返回對已儲存過程的描述。

CallableStatement 繼承 Statement 的方法(它們用於處理一般的 語句),還繼承了 PreparedStatement 的方法(它們用於處理 IN 引數)。CallableStatement 中定義的所有方法都用於處理 OUT 引數或 INOUT 引數的輸出部分:註冊 OUT 引數的 JDBC 型別(一般 SQL 型別)、從這些引數中檢索結果,或者檢查所返回的值是否為 JDBC NULL。


7.1.1 建立 CallableStatement 物件
CallableStatement 物件是用 Connection 方法 prepareCall 建立的。下例建立 CallableStatement 的例項,其中含有對已儲存過程 getTestData 呼叫。該過程有兩個變數,但不含結果引數:

CallableStatement cstmt = con.prepareCall(
"{call getTestData(?, ?)}");

其中 ? 佔位符為 IN、 OUT 還是 INOUT 引數,取決於已儲存過程 getTestData。


7.1.2 IN 和 OUT 引數
將 IN 引數傳給 CallableStatement 物件是透過 setXXX 方法完成的。該方法繼承自 PreparedStatement。所傳入引數的型別決定了所用的 setXXX 方法(例如,用 setFloat 來傳入 float 值等)。

如果已儲存過程返回 OUT 引數,則在 CallableStatement 物件以前必須先註冊每個 OUT 引數的 JDBC 型別(這是必需的,因為某些 DBMS 要求 JDBC 型別)。註冊 JDBC 型別是用 registerOutParameter 方法來完成的。語句執行完後,CallableStatement 的 getXXX 方法將取回引數值。正確的 getXXX 方法是為各引數所註冊的 JDBC 型別所對應的 Java 型別(從 JDBC 型別到 Java 型別的標準對映見 8.6.1 節中的表)。換言之, registerOutParameter 使用的是 JDBC 型別(因此它與資料庫返回的 JDBC 型別匹配),而 getXXX 將之轉換為 Java 型別。

作為示例,下述程式碼先註冊 OUT 引數,執行由 cstmt 所呼叫的已儲存過程,然後檢索在 OUT 引數中返回的值。方法 getByte 從第一個 OUT 引數中取出一個 Java 位元組,而 getBigDecimal 從第二個 OUT 引數中取出一個 BigDecimal 物件(小數點後面帶三位數):

CallableStatement cstmt = con.prepareCall(
"{call getTestData(?, ?)}");
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 3);
cstmt.executeQuery();
byte x = cstmt.getByte(1);
java.math.BigDecimal n = cstmt.getBigDecimal(2, 3);

CallableStatement 與 ResultSet 不同,它不提供用增量方式檢索大 OUT 值的特殊機制。


7.1.3 INOUT 引數
既支援輸入又接受輸出的引數(INOUT 引數)除了呼叫 registerOutParameter 方法外,還要求呼叫適當的 setXXX 方法(該方法是從 PreparedStatement 繼承來的)。setXXX 方法將引數值設定為輸入引數,而 registerOutParameter 方法將它的 JDBC 型別註冊為輸出引數。setXXX 方法提供一個 Java 值,而先把這個值轉換為 JDBC 值,然後將它送到資料庫中。

這種 IN 值的 JDBC 型別和提供給 registerOutParameter 方法的 JDBC 型別應該相同。然後,要檢索輸出值,就要用對應的 getXXX 方法。例如,Java 型別為 byte 的引數應該使用方法 setByte 來賦輸入值。應該給 registerOutParameter 提供型別為 TINYINT 的 JDBC 型別,同時應使用 getByte 來檢索輸出值 (第 8 節“JDBC 和 Java 型別之間的對映”將給出詳細資訊和型別對映表)。

下例假設有一個已儲存過程 reviseTotal,其唯一引數是 INOUT 引數。方法 setByte 把此引數設為 25,驅動程式將把它作為 JDBC TINYINT 型別送到資料庫中。接著,registerOutParameter 將該引數註冊為 JDBC TINYINT。執行完該已儲存過程後,將返回一個新的 JDBC TINYINT 值。方法 getByte 將把這個新值作為 Java byte 型別檢索。

CallableStatement cstmt = con.prepareCall(
"{call reviseTotal(?)}");
cstmt.setByte(1, 25);
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.executeUpdate();
byte x = cstmt.getByte(1);

7.1.4 先檢索結果,再檢索 OUT 引數
由於某些 DBMS 的限制,為了實現最大的可移植性,建議先檢索由執行 CallableStatement 物件所產生的結果,然後再用 CallableStatement.getXXX 方法來檢索 OUT 引數。

如果 CallableStatement 物件返回多個 ResultSet 物件(透過呼叫 execute 方法),在檢索 OUT 引數前應先檢索所有的結果。這種情況下,為確保對所有的結果都進行了訪問,必須對 Statement 方法 getResultSet、getUpdateCount 和 getMoreResults 進行呼叫,直到不再有結果為止。

檢索完所有的結果後,就可用 CallableStatement.getXXX 方法來檢索 OUT 引數中的值。


7.1.5 檢索作為 OUT 引數的 NULL 值
返回到 OUT 引數中的值可能會是 JDBC NULL。當出現這種情形時,將對 JDBC NULL 值進行轉換以使 getXXX 方法所返回的值為 null、0 或 false,這取決於 getXXX 方法型別。對於 ResultSet 物件,要知道 0 或 false 是否源於 JDBC NULL 的唯一方法,是用方法 wasNull 進行檢測。如果 getXXX 方法讀取的最後一個值是 JDBC NULL,則該方法返回 true,否則返回 flase。第 5 節“ResultSet”將給出詳細資訊。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-989810/,如需轉載,請註明出處,否則將追究法律責任。

相關文章