詳細介紹JDBC存儲過程
對已儲存過程的調(diào)用是CallableStatement對象所含的內(nèi)容。這種調(diào)用是用一種換碼語法來寫的,有兩種形式:一種形式帶結果參,另一種形式不帶結果參數(shù)。結果參數(shù)是一種輸出(OUT)參數(shù),是已儲存過程的返回值。兩種形式都可帶有數(shù)量可變的輸入(IN參數(shù))、輸出(OUT參數(shù))或輸入和輸出(INOUT參數(shù))的參數(shù)。問號將用作參數(shù)的占位符。
在JDBC中調(diào)用已儲存過程的語法如下所示。注意,方括號表示其間的內(nèi)容是可選項;方括號本身并非語法的組成部份。
{call過程名[(?,?,...)]}
返回結果參數(shù)的過程的語法為:
{?=call過程名[(?,?,...)]}
不帶參數(shù)的已儲存過程的語法類似:
{call過程名}
通常,創(chuàng)建CallableStatement對象的人應當知道所用的DBMS是支持已儲存過程的,并且知道這些過程都是些什么。然而,如果需要檢查,多種DatabaseMetaData方法都可以提供這樣的信息。例如,如果DBMS支持已儲存過程的調(diào)用,則supportsStoredProcedures方法將返回true,而getProcedures方法將返回對已儲存過程的描述。
CallableStatement繼承Statement的方法(它們用于處理一般的SQL語句),還繼承了PreparedStatement的方法(它們用于處理IN參)。
CallableStatement中定義的所有方法都用于處理OUT參數(shù)或INOUT參數(shù)的輸出部分:注冊OUT參數(shù)的JDBC類型(一般SQL類型)、從這些參數(shù)中檢索結果,或者檢查所返回的值是否為JDBCNULL。
JDBC存儲過程1、創(chuàng)建CallableStatement對象
CallableStatement對象是用Connection方法prepareCall創(chuàng)建的。下例創(chuàng)建CallableStatement的實例,其中含有對已儲存過程getTestData調(diào)用。該過程有兩個變量,但不含結果參數(shù):CallableStatementcstmt=con.prepareCall("{callgetTestData(?,?)}");其中?占位符為IN、OUT還是INOUT參數(shù),取決于已儲存過程getTestData。
JDBC存儲過程2、IN和OUT參數(shù)
將IN參數(shù)傳給CallableStatement對象是通過setXXX方法完成的。該方法繼承自PreparedStatement。所傳入?yún)?shù)的類型決定了所用的setXXX方法(例如,用setFloat來傳入float值等)。如果已儲存過程返回OUT參數(shù),則在執(zhí)行CallableStatement對象以前必須先注冊每個OUT參數(shù)的JDBC類型(這是必需的,因為某些DBMS要求JDBC類型)。注冊JDBC類型是用registerOutParameter方法來完成的。語句執(zhí)行完后,CallableStatement的getXXX方法將取回參數(shù)值。正確的getXXX方法是為各參數(shù)所注冊的JDBC類型所對應的Java類型。換言之,registerOutParameter使用的是JDBC類型(因此它與數(shù)據(jù)庫返回的JDBC類型匹配),而getXXX將之轉換為Java類型。
作為示例,下述代碼先注冊OUT參數(shù),執(zhí)行由cstmt所調(diào)用的已儲存過程,然后檢索在OUT參數(shù)中返回的值。方法getByte從***個OUT參數(shù)中取出一個Java字節(jié),而getBigDecimal從第二個OUT參數(shù)中取出一個BigDecimal對象(小數(shù)點后面帶三位數(shù)):
- CallableStatementcstmt=con.prepareCall("{callgetTestData(?,?)}");
- cstmt.registerOutParameter(1,java.sql.Types.TINYINT);
- cstmt.registerOutParameter(2,java.sql.Types.DECIMAL,3);
- cstmt.executeQuery();
- bytex=cstmt.getByte(1);
- java.math.BigDecimaln=cstmt.getBigDecimal(2,3);
CallableStatement與ResultSet不同,它不提供用增量方式檢索大OUT值的特殊機制。
JDBC存儲過程3、INOUT參數(shù)
既支持輸入又接受輸出的參數(shù)(INOUT參數(shù))除了調(diào)用registerOutParameter方法外,還要求調(diào)用適當?shù)膕etXXX方法(該方法是從PreparedStatement繼承來的)。setXXX方法將參數(shù)值設置為輸入?yún)?shù),而registerOutParameter方法將它的JDBC類型注冊為輸出參數(shù)。setXXX方法提供一個Java值,而驅(qū)動程序先把這個值轉換為JDBC值,然后將它送到數(shù)據(jù)庫中。這種IN值的JDBC類型和提供給registerOutParameter方法的JDBC類型應該相同。然后,要檢索輸出值,就要用對應的getXXX方法。例如,Java類型為byte的參數(shù)應該使用方法setByte來賦輸入值。應該給registerOutParameter提供類型為TINYINT的JDBC類型,同時應使用getByte來檢索輸出值。
下例假設有一個已儲存過程reviseTotal,其唯一參數(shù)是INOUT參數(shù)。方法setByte把此參數(shù)設為25,驅(qū)動程序?qū)阉鳛镴DBCTINYINT類型送到數(shù)據(jù)庫中。接著,registerOutParameter將該參數(shù)注冊為JDBCTINYINT。執(zhí)行完該已儲存過程后,將返回一個新的JDBCTINYINT值。方法getByte將把這個新值作為Javabyte類型檢索。
- CallableStatementcstmt=con.prepareCall("{callreviseTotal(?)}");
- cstmt.setByte(1,25);
- cstmt.registerOutParameter(1,java.sql.Types.TINYINT);
- cstmt.executeUpdate();
- bytex=cstmt.getByte(1);
JDBC存儲過程4、先檢索結果,再檢索OUT參數(shù)
由于某些DBMS的限制,為了實現(xiàn)***的可移植性,建議先檢索由執(zhí)行CallableStatement對象所產(chǎn)生的結果,然后再用CallableStatement.getXXX方法來檢索OUT參數(shù)。如果CallableStatement對象返回多個ResultSet對象(通過調(diào)用execute方法),在檢索OUT參數(shù)前應先檢索所有的結果。這種情況下,為確保對所有的結果都進行了訪問,必須對Statement方法getResultSet、getUpdateCount和getMoreResults進行調(diào)用,直到不再有結果為止。
檢索完所有的結果后,就可用CallableStatement.getXXX方法來檢索OUT參數(shù)中的值。
JDBC存儲過程5、檢索作為OUT參數(shù)的NULL值
返回到OUT參數(shù)中的值可能會是JDBCNULL。當出現(xiàn)這種情形時,將對JDBCNULL值進行轉換以使getXXX方法所返回的值為null、0或false,這取決于getXXX
方法類型。對于ResultSet對象,要知道0或false是否源于JDBCNULL的唯一方法,是用方法wasNull進行檢測。如果getXXX方法讀取的***一個值是JDBCNULL,則該方法返回true,否則返回flase。多個參數(shù)或者沒有參數(shù)就是改變這里多個參數(shù)cstmt.setString(1,str);
.
.
.
n
cstmt.registerOutParameter(n+1,oracle.jdbc.OracleTypes.CURSOR);
沒有參數(shù)就是直接
cstmt.registerOutParameter(1,[/color]oracle.jdbc.OracleTypes.CURSOR);
【編輯推薦】
<