oracle 對於進階特性總是與眾不同(我極力討厭這一點,如果使用它的產品就要對這種產品進行特定的編程,這也是我從不看好weblogic之類的平台的原因),大對象存取一要定用它自己的LOB對象,所幸我還能通過LONG RAW來代替。以便能使程式不需要特定的編碼。但對於預存程序(我是說返回結果集的預存程序),我還沒有什麼方法能用一個通用的程式來處理ORACLE。太多的教材或文章在講預存程序的調用只是不負責任地簡單執行一些涵數或無結果返回的預存程序,使大多數讀者根本不知道到底如何調用預存程序的結果集。而在Spring中,根本就沒有真正完全地介紹對預存程序的結果集的處理,更別說象oracle這種"特別"的預存程序的結果集處理。先來簡單看一下我們如何在JDBC中處理預存程序的結果集的通用流程:
1、擷取CallableStatement語句:
CallableStatement cs = conn. prepareCall("{call spName(?,?,?)}");
2、傳入輸入參數和註冊輸出參數
cs. setXXX(index,value);//輸入參數
cs. registerOutParameter(index,type);//輸出參數
3、執行預存程序:
cs.execute();
對於一個存諸過程,如果返回的結果是我們預Crowdsourced Security Testing道的,那麼可以根據預存程序定義的順序來進行處理(事實上一般不會這樣),但對於複雜的多結果集的處理,如何定義一個通用的流程?我們先看一下JDBC本身能為我們提供什麼?
一個預存程序執行後返回的是boolean型:
boolean flag = callableStatement. execute();
如果flag為true,那麼說明返回了一個結果集(ResultSet)類型,你可以用getResultSet()得到當前行所在的結果,而如果返回為flase,說明什麼呢?如果你不進行處理,什麼也不能說明,只能說明當前指標不是ResultSet,有可能是更新計數(updateCount)也可能什麼也沒有反應。
那麼如果當前指標為flase時如何處理?我們應該先getUpdateCount();如果返回-1,既不是結果集,又不是更新計數了。說明沒的返回了。而如果getUpdateCount()返回0或大於0,則說明當前指標是更新計數(0的時候有可能是DDL指令)。無論是返回結果集或是更新計數,那麼則可能還繼續有其它返回。只有在當前指指標getResultSet()==null && getUpdateCount() == -1才說明沒有再多的返回。
預存程序的返回和ResultSet類似,每次處理的返回結果相當於是ResultSet的Row,只不過預存程序的Row,最先在第一行而不是象ResultSet要先next才到第一行,預存程序向下移動一行用getMoreResults(),相當於ResultSet的next()。同樣它返回boolean和上面的flag一樣,只是說明當前行是不是ResultSet,如果是flase,你還是要判斷是不是updateCount,在每一行,都要先同時判斷是否為ResultSet還是UpdateCount,如果是其中一種則要繼續getMoreResults(),當不是ResultSet也不是updateCount時,說明沒有返回結果了,這時再擷取輸出參數。
看明白了嗎?那我們就根據上面的規則來寫一個通用的流程吧:
首先,我們要確定什麼時候沒說結果集了:
if(cs.getResultSet() == null && cs. getUpdateCount() == -1)
現在我們做一個迴圈:
ResultSet rs = null;
int updateCount = -1;
flag = cs。execute();
do{
updateCount = cs。getUpdateCount();
if(updateCount != -1){//說明當前行是一個更新計數
//處理。
cs。getMoreResults();
continue;//已經是更新計數了,處理完成後應該移動到下一行
//不再判斷是否是ResultSet
}
rs = cs。getResultSet();
if(rs != null){//如果到了這裡,說明updateCount == -1
//處理rs
cs。getMoreResults();
continue;
//是結果集,處理完成後應該移動到下一行
}
//如果到了這裡,說明updateCount == -1 && rs == null,什麼也沒的了
}while(!(updateCount == -1 && rs == null));
cs.getXXX(int);//擷取輸出參數