1. 程式人生 > >星月--- Java探索之路

星月--- Java探索之路

 儲存過程是儲存在資料庫中的一個訪問資料庫的程式程式碼,一個儲存過程物件提供了一種訪問所有關係型資料庫的儲存過程的方法。

一個CallableStatement物件中包含了對一個儲存過程的呼叫,這種呼叫可以用2種形式表式:一個形式是用一個結果引數,另一種形式則不用結果引數。結果引數指的是OUT引數,就是儲存過程返回的值。

在JDBC開發中,可以通過呼叫DatabaseMeta物件的方法來檢驗資料庫是否支援儲存過程。方法supportsStoreProcedures會檢測資料庫系統是否支援儲存過程,使用這個方法並對其返回的結果進行判斷,如返回true,那麼支援儲存過程,否則不支援。而方法getProcedures會返回所有可用的儲存過程的描述。

1、CallableStatement物件的建立

Connection conn;
......

CallableStatement cstmt
=conn.prepareCall ( "call getTestData (?, ?) } "); // "?"所代表的引數的型別取決於儲存過程getTestData,根據getTestData的不同, "?"可能為IN引數、OUT引數 // 或INOUT引數中的一種 //建立可滾動可更新結果集的CallableStatement物件
String sql="{call getTestData ( ?, ?) }";
CallableStatement cstmt
=conn.prepareCall ( sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

 2、 IN、OUT 及 INOUT引數的引用

CallableStatement物件可以使用3種類型的引數:IN, OUT, INOUT。引數可以通過引數名來指定也可以通過引數的序號來指定,對每一個語句中的引數都要賦值,否則就不能執行。

一個儲存過程中的引數數目、型別和屬性可以通過DatabaseMetaData的getProcedureColumn方法來獲得。

被傳遞到CallableStatement中的引數的序號是按照statement中"?"的順序而確定的,如果存在文字引數,不計算文字引數,如:

//採用指定序號的方式進行引數賦值 CallableStatement cstmt=conn.prepareCall ( "{ call proc ( ?, "Literal_Value" ,  ? ) } ");
cstmt.setString (
1"First");
cstmt.setString (
2"Third");

引數的賦值還可以用命名引數的方式來進行,這種方式對於一個有很多預設引數值的過程特別有用,但命名的引數只能用來指定沒有預設值的引數,且這個引數的名稱是和列名相關的,可以用DatabaseMetaData.getProcedureColumns方法來取得。

方法DatabaseMetaData.supportsNamedParameters可以用來檢驗JDBC驅動程式和底層的資料來源是否支援用引數名設定引數。

對於一個OUT引數來說,registerOutParameter方法一定要在CallableStatement物件被執行之前呼叫以設定OUT引數型別,當一個儲存過程從一個執行中返回後,它會用這些型別設定OUT引數的值,可以用CallableStatement中定義的getXXX方法來獲取OUT引數的值。

//獲取OUT引數
CallableStatement cstmt=conn.prepareCall ( "{ call get_name_and_number (? , ?) }" );
cstmt.registerOutParameter ( 
1, java.sql.Types.STRING);
cstmt.registerOutParameter ( 
2, java.sql.Types.FLOAT) ; 
cstmt.Execute ( ) ;
String name 
= cstmt.getString (1 );
float number = cstmt. getFloat (2 );

INOUT既是輸入引數又是輸出引數,因此必須使用適當的setXXX方法和註冊方法registerOutParameter來進行初始化,setXXX中的XXX型別必須和registerOutParameter中的引數型別相匹配。

//INOUT引數的使用方法
CallableStatement cstmt = conn.prepareCall ( " { call calc ( ? ) } ");
cstmt.setFloat (
11237.98f);
cstmt.registerOutParameter ( 
1, java.sql.Types.FLOAT );
cstmt.Execute ( ) ;
float f= cstmt. getFloat (1 );

3、執行CallableStatementObject物件

執行一個CallableStatementObject物件的返回結果可能有三種:

1)返回結果集

CallableStatement cstmt = conn.prepareCall ( " { call getinfo ( ? ) } ");
cstmt.setLong (
11309944422);
ResultSet rs 
= cstmt. ExecuteQuery ();
while ( rs.next() ) {
......
 }

rs.close();
cstmt.close();

2) 返回更新數目

CallableStatement cstmt = conn . prepareCall ( " { call getcount ( ? ) } " );
cstmt.setString ( 
1"Smith"); 
int count=cstmt.ExecuteUpdate();
cstmt.close();

3) 如果CallableStatement返回的結果的型別和數量並不能提前知道,CallableStatement應該使用Execute方法來執行語句,並使用函式getMoreResults, getUpdateCount和 getResultSet幫助獲取全部的返回結果。

CallableStatement cstmt = conn. prepareCall ( procCall ); 
boolean retval = cstmt. Execute();
ResultSet rs;
int count; 
do{
if (retval ==false{
count 
= cstmt. getUpdateCount();
if (count ==-1){
break
}
else{
//處理行數目
}

}
else{
//結果集
rs = cstmt.getResultSet();
//處理結果集
retval = cstmt.getMoreResults();
}
while(true);

預設情況下,當呼叫一次getMoreResults時,就會將以前產生的ResultSet物件關閉,但getMoreResults可以使用一些引數以決定由前面的getResultSet函式獲取的ResultSet物件是否關閉。

CLOSE_CURRENT_RESULT:當前的結果集在下一個結果集產生時關閉

KEEP_CURRENT_RESULT:當前的結果集在下一個結果集產生時可不被關閉

CLOSE_ALL_RESULT:當下一個結果集產生的時候,關閉所有保持的結果物件

為了確定一個驅動程式是否實現了這種特性,可以呼叫DatabaseMetaData介面的supportsMultipleOpenResults函式來檢測。

ResultSet rs1 = cstmt. getResultSet();
rs1.next();
....
retval 
= cstmt. getMoreResults (Statement.KEEP_CURRENT_RESULT);
if (retval ==true){
ResultSet rs2 
= cstmt. getResultSet();
rs2. next();
....
rs1. next();
}

retval 
= cstmt. getMoreResults (Statement.CLOSE_ALL_RESULTS);