前幾天項目里數(shù)據(jù)存儲支持了存儲過程,當(dāng)時趕進度,只是簡單的拿SQL Server 2000做了測試。今天同事要用Oracle9i數(shù)據(jù)庫,于是研究了一下Oracle的存儲過程,不看不知道啊,居然Oracle里要支持存儲過程如此復(fù)雜??!上網(wǎng)查資料,自己做實驗,終于弄了大半夜才鼓搗出來!
項目里的需求很簡單:通過一個存儲過程返回一個數(shù)據(jù)集(當(dāng)然,我只負責(zé)簡單調(diào)用存儲過程,存儲過程內(nèi)部可能很復(fù)雜了^_^)。不同于SQL Server 2000的存儲過程,Oracle里的存儲過程分為procedure和function兩種,如果用procedure的話,無法直接返回結(jié)果集,讀取結(jié)果集的方式比較復(fù)雜;function是可以返回結(jié)果集的存儲過程,調(diào)用相對簡單些。
下面的介紹將以一張BOOK表的查詢?yōu)槔?/div>
create table BOOK
(
BOOKNUMBER CHAR(3) not null,
BOOKNAME VARCHAR2(50),
BOOKPRICE NUMBER(18,2)
)
要返回數(shù)據(jù)集,就需要使用Oracle里的reference cursor類型,不過Oracle里這個類型用的方式比較羅唆(搞不明白Oracle為什么要弄的這么復(fù)雜),首先要聲明一個引用的cursor類型,這個通過創(chuàng)建一個包來實現(xiàn):
CREATE OR REPLACE PACKAGE PKG_TEST
AS
TYPE REFCURSOR IS REF CURSOR;
END PKG_TEST;
然后創(chuàng)建我們的function存儲過程:
create or replace function query_book(key varchar) return PKG_TEST.REFCURSOR is
Result PKG_TEST.REFCURSOR;
begin
open Result for
select * from book where key=book.booknumber;
return(Result);
end query_book;
在這個存儲過程中,我們傳入了查詢鍵值key,返回了一個數(shù)據(jù)集對象
這樣我們就有了一個名為query_book的存儲過程,它可以返回一個結(jié)果數(shù)據(jù)集。要調(diào)用這個存儲過程,可以通過CallableStatement接口來調(diào)用,這樣需要寫成類似'{?=call query_book(?)}'的查詢語句,并且參數(shù)和返回值都必須用代碼設(shè)置;在這里,一些簡單的存儲過程,也可以通過查詢來調(diào)用。下面就是我使用的調(diào)用方法:
public class FuncTest {
public static void main(String[] args) throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:LeeDB",
"TEST", "test");
Statement stmt = connection.createStatement();
ResultSet dataset = stmt.executeQuery("SELECT query_book('001') FROM DUAL");
if (dataset.next()) {
ResultSet ret = (ResultSet)dataset.getObject(1);
while( ret.next() ) {
System.out.print(ret.getString(1));
System.out.print("\t");
System.out.print(ret.getString(2));
System.out.print("\t");
System.out.println(ret.getDouble(3));
}
}
}
}
注意這里返回的數(shù)據(jù)集中內(nèi)嵌了function返回的數(shù)據(jù)集,需要進行特殊處理。
上面代碼執(zhí)行之后可以成功返回結(jié)果: