java資料庫的存儲過程
Java調用存儲過程的方法是通過調用Connection的實例方法prepareCall,prepareCall方法返回CallableStatement對象用於填充存儲過程的參數。prepareCall方法形參是調用存儲過程的sql語句,此參數的語法格式如下:
{callstoredProcereName(parameter-list)}
其中,storedProcereName是存儲過程名稱,parameter-list是存儲過程參數列表。
例如,存儲過程名為usp_test,有兩個輸入參數a,b。則調用代碼看起來如下所示:
=connection.prepareCall("{callusp_test(?,?)}");
callableStatement.setObject("a","value-1");
callableStatement.setObject("b","value-2");
callableStatement.execute();
⑵ java裡面怎麼調用存儲過程
最近做一個自動發郵件的schele,由於取數據的sql太長,直接分割很麻煩,就想到調用PL/SQL,網上查了資料做了練習,在此做下小結。
1、只有輸入參數而沒有返回結果的存儲過程。
sql:
1 create or replace procere prc_1(deptno in number,dname in varchar2,loc in varchar2)
2 is
3 begin
4 insert into dept values(deptno,dname,loc);
5 end prc_1;
java:
1 static void test1(){
2 Connection conn=null;
3 CallableStatement csmt=null;
4 try {
5 conn=JDBCUtils.getConnection();
6 conn.setAutoCommit(false);
7 csmt=conn.prepareCall("call prc_1(?,?,?)");
8 csmt.setInt(1,80);
9 csmt.setString(2,"ioc");
10 csmt.setString(3,"fhp");
11 csmt.execute();
12 conn.commit();
13 System.out.println("success insert data");
14 } catch (SQLException e) {
15 e.printStackTrace();
16 }
17 }
2、有輸入參數且有一個返回值的存儲過程。
sql:
1 create or replace procere prc_2(p_deptno in number,p_loc out varchar2) is
2 begin
3 select loc into p_loc from dept where deptno=p_deptno;
4 end prc_2;
java:
1 static void test2(){
2 Connection conn=null;
3 CallableStatement csmt=null;
4 try {
5 conn=JDBCUtils.getConnection();
6 conn.setAutoCommit(false);
7 csmt=conn.prepareCall("call prc_2(?,?)");
8 csmt.setInt(1,70);
9 csmt.registerOutParameter(2,Types.VARCHAR);
10 csmt.execute();
11 conn.commit();
12 System.out.println("MIS位置:"+csmt.getString(2));
13 } catch (SQLException e) {
14 e.printStackTrace();
15 }
16 }
3、返回多行記錄(游標)的存儲過程。
sql:
首先要建立一個返回遊標,以便接收返回結果。
1 create or replace package testpackage is
2 type test_cursor is ref cursor;
3 end testpackage;
4
5 create or replace procere prc_3(p_cursor out testpackage.test_cursor)is
6 begin
7 open p_cursor for
8 select * from dept order by deptno;
9 end prc_3;
java:
1 static void test3(){
2 Connection conn=null;
3 CallableStatement csmt=null;
4 ResultSet rs=null;
5 try {
6 conn=JDBCUtils.getConnection();
7 conn.setAutoCommit(false);
8 csmt=conn.prepareCall("call prc_3(?)");
9 csmt.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);
10 csmt.execute();
11 rs=(ResultSet) csmt.getObject(1);
12 while(rs.next()){
13 System.out.println(rs.getString("deptno")+'\t'+rs.getString("dname")+'\t'+rs.getString("loc"));
14 }
15 } catch (SQLException e) {
16 // TODO Auto-generated catch block
17 e.printStackTrace();
18 }finally{
19 JDBCUtils.free(rs, csmt, conn);
20 }
21 }
⑶ java裡面怎麼調用mysql的存儲過程的
java代碼:
Class.forName("com.mysql.jdbc.Driver");
Connectioncon=DriverManager
.getConnection("jdbc:mysql://localhost:3306/test?user=root&password=111111");
Stringsql="{callsel(?)}";
CallableStatementcs=(CallableStatement)con.prepareCall(sql);
cs.execute();
Stringname=cs.getString(1);
System.out.println(name);
創建存儲過程代碼:
dropprocereifexistssel;
createproceresel(outname1varchar(225))
begin
;
end
輸出結果:
⑷ Java資料庫程序中的存儲過程設計
本文闡述了怎麼使用DBMS存儲過程 闡述了使用存儲過程的基本的和高級特性 比如返回ResultSet 本文假設你對DBMS和JDBC已經非常熟悉 也假設你能夠毫無障礙地閱讀其它語言寫成的代碼(即不是Java的語言) 但是 並不要求你有任何存儲過程的編程經歷
存儲過程是指保存在數據豎拿庫並在資料庫端執行的程序 你可以使用特殊的語法在Java類中調用存儲過程 在調用時 存儲過程的名稱及指定的參數通過JDBC連接發送給DBMS 執行存儲過程並通過連接(如果有)返回結果
使用存儲過程擁有和使用基於EJB或CORBA這樣的應用伺服器一樣的好處 區別是存儲過程可以從很多流行的DBMS中免費使用 而應用伺服器大都非常昂貴 這並不只是許可證費用的問題 使用應用伺服器所需要花費的管理 編寫代碼的費用 以及客戶程序所增加的復雜性 都可以通過DBMS中的存儲過程所整個地替代
你可以使用Java Python Perl或C編寫存儲過程 但是通常使用你的DBMS所指定的特定語言 Oracle使用PL/SQL PostgreSQL使用pl/pgsql DB 使用Proceral SQL 這些語言都非常相似 在它們之間移植存儲過程並不比在Sun的EJB規范不同實現版本之間移植Session Bean困難 並且 存儲過程是為嵌入SQL所設計 這使得它們比Java或C等語言更加友好地方式表達資料庫的機制
因為存儲過程運行在DBMS自身 這可以幫助減少應用程序中的等待時間 不是在Java代碼中執行 個或 個SQL語句 而只需要在伺服器端執行 個存儲過程 網路上的數據往返次數的減少可以戲劇性地優化性能
使用存儲過程
簡單的老的JDBC通過CallableStatement類支持存儲過程的調用 該類實際上是PreparedStatement的一個子類 假設我們有一個poets資料庫 資料庫中有一個設置詩人逝世年齡的存儲過程 下面是對老酒鬼Dylan Thomas(old soak Dylan Thomas 不指定是否有關典故跡灶 文化 請批評指正 譯注)進行調用的詳細代碼
try{int age = ;String poetName = dylan thomas ;CallableStatement proc = connection prepareCall( { call set_death_age(? ?) } );proc setString( poetName);proc setInt( age);cs execute();}catch (SQLException e){// }
傳給prepareCall方法的字串是存儲過程調用的書寫規范 它指定了存儲過程的名稱 ?代表了你需要指定的參數
和JDBC集成是存儲過程的一個很大的便利 為了從應用中調用存儲過程 不需要存根(stub)類或者配置文件 除了你的DBMS的JDBC驅動程序外什麼也不需要
當這段代碼執行時 資料庫的存儲過程就被調用 我們沒有去獲取結果 因為該存儲過程並不返回結果 執行成功或失敗將通過例外得知 失敗可能意味著調用存儲姿纖扮過程時的失敗(比如提供的一個參數的類型不正確) 或者一個應用程序的失敗(比如拋出一個例外指示在poets資料庫中並不存在 Dylan Thomas )
結合SQL操作與存儲過程
映射Java對象到SQL表中的行相當簡單 但是通常需要執行幾個SQL語句 可能是一個SELECT查找ID 然後一個INSERT插入指定ID的數據 在高度規格化(符合更高的範式 譯注)的資料庫模式中 可能需要多個表的更新 因此需要更多的語句 Java代碼會很快地膨脹 每一個語句的網路開銷也迅速增加
將這些SQL語句轉移到一個存儲過程中將大大簡化代碼 僅涉及一次網路調用 所有關聯的SQL操作都可以在資料庫內部發生 並且 存儲過程語言 例如PL/SQL 允許使用SQL語法 這比Java代碼更加自然 下面是我們早期的存儲過程 使用Oracle的PL/SQL語言編寫
create procere set_death_age(poet VARCHAR poet_age NUMBER)poet_id NUMBER;beginSELECT id INTO poet_id FROM poets WHERE name = poet;INSERT INTO deaths (mort_id age) VALUES (poet_id poet_age);end set_death_age;
很獨特?不 我打賭你一定期待看到一個poets表上的UPDATE 這也暗示了使用存儲過程實現是多麼容易的一件事情 set_death_age幾乎可以肯定是一個很爛的實現 我們應該在poets表中添加一列來存儲逝世年齡 Java代碼中並不關心資料庫模式是怎麼實現的 因為它僅調用存儲過程 我們以後可以改變資料庫模式以提高性能 但是我們不必修改我們代碼
下面是調用上面存儲過程的Java代碼
public static void setDeathAge(Poet dyingBard int age)throws SQLException{Connection con = null;CallableStatement proc = null;
try{con = connectionPool getConnection();proc = con prepareCall( { call set_death_age(? ?) } );proc setString( dyingBard getName());proc setInt( age);proc execute();}finally{try{proc close();}catch (SQLException e) {}con close();}}
為了確保可維護性 建議使用像這兒這樣的static方法 這也使得調用存儲過程的代碼集中在一個簡單的模版代碼中 如果你用到許多存儲過程 就會發現僅需要拷貝 粘貼就可以創建新的方法 因為代碼的模版化 甚至也可以通過腳本自動生產調用存儲過程的代碼
Functions
存儲過程可以有返回值 所以CallableStatement類有類似getResultSet這樣的方法來獲取返回值 當存儲過程返回一個值時 你必須使用registerOutParameter方法告訴JDBC驅動器該值的SQL類型是什麼 你也必須調整存儲過程調用來指示該過程返回一個值
下面接著上面的例子 這次我們查詢Dylan Thomas逝世時的年齡 這次的存儲過程使用PostgreSQL的pl/pgsql
create function snuffed_it_when (VARCHAR) returns integer declarepoet_id NUMBER;poet_age NUMBER;begin first get the id associated with the poet SELECT id INTO poet_id FROM poets WHERE name = $ ; get and return the age SELECT age INTO poet_age FROM deaths WHERE mort_id = poet_id;return age;end; language pl/pgsql ;
另外 注意pl/pgsql參數名通過Unix和DOS腳本的$n語法引用 同時 也注意嵌入的注釋 這是和Java代碼相比的另一個優越性 在Java中寫這樣的注釋當然是可以的 但是看起來很凌亂 並且和SQL語句脫節 必須嵌入到Java String中
下面是調用這個存儲過程的Java代碼
connection setAutoCommit(false);CallableStatement proc =connection prepareCall( { ? = call snuffed_it_when(?) } );proc registerOutParameter( Types INTEGER);proc setString( poetName);cs execute();int age = proc getInt( );
如果指定了錯誤的返回值類型會怎樣?那麼 當調用存儲過程時將拋出一個RuntimeException 正如你在ResultSet操作中使用了一個錯誤的類型所碰到的一樣
復雜的返回值
關於存儲過程的知識 很多人好像就熟悉我們所討論的這些 如果這是存儲過程的全部功能 那麼存儲過程就不是其它遠程執行機制的替換方案了 存儲過程的功能比這強大得多
當你執行一個SQL查詢時 DBMS創建一個叫做cursor(游標)的資料庫對象 用於在返回結果中迭代每一行 ResultSet是當前時間點的游標的一個表示 這就是為什麼沒有緩存或者特定資料庫的支持 你只能在ResultSet中向前移動
某些DBMS允許從存儲過程中返回遊標的一個引用 JDBC並不支持這個功能 但是Oracle PostgreSQL和DB 的JDBC驅動器都支持在ResultSet上打開到游標的指針(pointer)
設想列出所有沒有活到退休年齡的詩人 下面是完成這個功能的存儲過程 返回一個打開的游標 同樣也使用PostgreSQL的pl/pgsql語言
create procere list_early_deaths () return refcursor as declaretoesup refcursor;beginopen toesup forSELECT poets name deaths ageFROM poets deaths all entries in deaths are for poets but the table might bee generic WHERE poets id = deaths mort_idAND deaths age < ;return toesup;end; language plpgsql ;
下面是調用該存儲過程的Java方法 將結果輸出到PrintWriter
PrintWriter:
static void sendEarlyDeaths(PrintWriter out){Connection con = null;CallableStatement toesUp = null;try{con = ConnectionPool getConnection();
// PostgreSQL needs a transaction to do this con setAutoCommit(false);
// Setup the call CallableStatement toesUp= connection prepareCall( { ? = call list_early_deaths () } );toesUp registerOutParameter( Types OTHER);getResults execute();
ResultSet rs = (ResultSet) getResults getObject( );while (rs next()){String name = rs getString( );int age = rs getInt( );out println(name + was + age + years old );}rs close();}catch (SQLException e){// We should protect these calls toesUp close();con close();}}
因為JDBC並不直接支持從存儲過程中返回遊標 我們使用Types OTHER來指示存儲過程的返回類型 然後調用getObject()方法並對返回值進行強制類型轉換
這個調用存儲過程的Java方法是mapping的一個好例子 Mapping是對一個集上的操作進行抽象的方法 不是在這個過程上返回一個集 我們可以把操作傳送進去執行 本例中 操作就是把ResultSet列印到一個輸出流 這是一個值得舉例的很常用的例子 下面是調用同一個存儲過程的另外一個方法實現
public class ProcessPoetDeaths{public abstract void sendDeath(String name int age);}
static void mapEarlyDeaths(ProcessPoetDeaths mapper){Connection con = null;CallableStatement toesUp = null;try{con = ConnectionPool getConnection();con setAutoCommit(false);
CallableStatement toesUp= connection prepareCall( { ? = call list_early_deaths () } );toesUp registerOutParameter( Types OTHER);getResults execute();
ResultSet rs = (ResultSet) getResults getObject( );while (rs next()){String name = rs getString( );int age = rs getInt( );mapper sendDeath(name age);}rs close();}catch (SQLException e){// We should protect these calls toesUp close();con close();}}
這允許在ResultSet數據上執行任意的處理 而不需要改變或者復制獲取ResultSet的方法
static void sendEarlyDeaths(final PrintWriter out){ProcessPoetDeaths myMapper = new ProcessPoetDeaths(){public void sendDeath(String name int age){out println(name + was + age + years old );}};mapEarlyDeaths(myMapper);}
這個方法使用ProcessPoetDeaths的一個匿名實例調用mapEarlyDeaths 該實例擁有sendDeath方法的一個實現 和我們上面的例子一樣的方式把結果寫入到輸出流 當然 這個技巧並不是存儲過程特有的 但是和存儲過程中返回的ResultSet結合使用 是一個非常強大的工具
結論
存儲過程可以幫助你在代碼中分離邏輯 這基本上總是有益的 這個分離的好處有
快速創建應用 使用和應用一起改變和改善的資料庫模式
資料庫模式可以在以後改變而不影響Java對象 當我們完成應用後 可以重新設計更好的模式
存儲過程通過更好的SQL嵌入使得復雜的SQL更容易理解
編寫存儲過程比在Java中編寫嵌入的SQL擁有更好的工具——大部分編輯器都提供語法高亮!
存儲過程可以在任何SQL命令行中測試 這使得調試更加容易
並不是所有的資料庫都支持存儲過程 但是存在許多很棒的實現 包括免費/開源的和非免費的 所以移植並不是一個問題 Oracle PostgreSQL和DB 都有類似的存儲過程語言 並且有在線的社區很好地支持
存儲過程工具很多 有像TOAD或TORA這樣的編輯器 調試器和IDE 提供了編寫 維護PL/SQL或pl/pgsql的強大的環境
lishixin/Article/program/Java/hx/201311/25906
⑸ JAVA用代碼操作資料庫創建表,視圖,觸發器,存儲過程等。
create
or
replace
trigger
trg_delete_count
before
delete
on
student
for
each
row
begin
delete
from
成績表
where
成績表.學號=:old.學號;
commit;
end;
想要實現類似的功能,不一定要用觸發器的,可以設置兩個表的主鍵和外鍵,設置級聯刪除關系,刪除主鍵時,外鍵表中的記錄也會自動刪除。
⑹ 如何創建Java存儲過程
1、操作系統:windows 2000 Server
2、數 據 庫:Oracle 8i R2 (8.1.7) for NT 企業版
3、安裝路徑:C:\ORACLE
實現方法:
1、 創建一個文件為TEST.java
public class TEST
{
public static void main (String args[])
{
System.out.PRintln("HELLO THIS iS A JAVA PROCEDURE");
}
}
2、 javac TEST.java
3、 java TEST
4、 SQL> conn system/manager
SQL> grant create any Directory to scott;
SQL> conn scott/tiger
SQL> create or replace directory test_dir as 'd:\'
目錄已創建。
SQL> create or replace java class using bfile(test_dir,'TEST.CLASS')
2/
Java 已創建。
SQL> select object_name,object_type,STATUS from user_objects;
SQL> create or replace procere test_java
as language java
name 'TEST.main(java.lang.String[])';
/
過程已創建。
SQL> set serveroutput on size 5000
SQL> call dbms_java.set_output(5000);
調用完成。
SQL> execute test_java;
HELLO THIS iS A JAVA PROCEDURE
PL/SQL 過程已成功完成。
SQL> call test_java();
HELLO THIS iS A JAVA PROCEDURE
調用完成。
⑺ 如何用JAVA調用存儲過程
已儲存過程儲存在資料庫中。對已儲存過程的調用是 CallableStatement對象所含的內容。這種調用是用一種換碼語法來寫的,有兩種形式:一種形式帶結果參,另一種形式不帶結果參數。結果參數是一種輸出 (OUT) 參數,是已儲存過程的返回值。兩種形式都可帶有數量可變的輸入(IN 參數)、輸出(OUT 參數)或輸入和輸出(INOUT 參數)的參數。問號將用作參數的佔位符。 在JDBC 中調用已儲存過程的語法如下所示。注意,方括弧表示其間的內容是可選項;方括弧本身並不是語法的組成部份。{call 過程名[(?, ?, ...)]} 返回結果參數的過程的語法為:{? = call 過程名[(?, ?, ...)]} 不帶參數的已儲存過程的語法類似:{call 過程名} 通常,創建 CallableStatement 對象的人應當知道所用的 DBMS 是支持已儲存過程的,並且知道這些過程都是些什麼。然而,如果需要檢查,多種DatabaseMetaData 方法都可以提供這樣的信息。例如,如果 DBMS 支持已儲存過程的調用,則supportsStoredProceres 方法將返回 true,而getProceres 方法將返回對已儲存過程的描述。CallableStatement 繼承 Statement 的方法(它們用於處理一般的 SQL 語句),還繼承了 PreparedStatement 的方法(它們用於處理 IN 參)。 CallableStatement 中定義的所有方法都用於處理 OUT 參數或 INOUT 參數的輸出部分:注冊 OUT 參數的 JDBC 類型(一般 SQL 類型)、從這些參數中檢索結果,或者檢查所返回的值是否為 JDBC NULL。 1、創建 CallableStatement 對象 CallableStatement 對象是用 Connection 方法 prepareCall 創建的。下例創建 CallableStatement 的實例,其中含有對已儲存過程 getTestData 調用。該過程有兩個變數,但不含結果參數:CallableStatement cstmt = con.prepareCall("{call getTestData(?, ?)}"); 其中?佔位符為IN、OUT還是INOUT參數,取決於已儲存過程getTestData。 2、IN和OUT參數 將IN參數傳給 CallableStatement 對象是通過 setXXX 方法完成的。該方法繼承自 PreparedStatement。所傳入參數的類型決定了所用的setXXX方法(例如,用 setFloat 來傳入 float 值等)。 如果已儲存過程返回 OUT 參數,則在執行 CallableStatement 對象以前必須先注冊每個 OUT 參數的 JDBC 類型(這是必需的,因為某些 DBMS 要求 JDBC 類型)。注冊 JDBC 類型是用 registerOutParameter 方法來完成的。語句執行完後,CallableStatement 的 getXXX 方法將取回參數值。正確的 getXXX 方法是為各參數所注冊的 JDBC 類型所對應的 Java 類型。換言之, 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 值的特殊機制。3、INOUT參數 既支持輸入又接受輸出的參數(INOUT 參數)除了調用 registerOutParameter 方法外,還要求調用適當的 setXXX 方法(該方法是從 PreparedStatement 繼承來的)。setXXX 方法將參數值設置為輸入參數,而 registerOutParameter 方法將它的 JDBC 類型注冊為輸出參數。setXXX 方法提供一個 Java 值,而驅動程序先把這個值轉換為 JDBC 值,然後將它送到資料庫中。這種 IN 值的 JDBC 類型和提供給 registerOutParameter 方法的 JDBC 類型應該相同。然後,要檢索輸出值,就要用對應的 getXXX 方法。例如,Java 類型為byte 的參數應該使用方法 setByte 來賦輸入值。應該給registerOutParameter 提供類型為 TINYINT 的 JDBC 類型,同時應使用 getByte 來檢索輸出值。 下例假設有一個已儲存過程 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); 4、先檢索結果,再檢索 OUT 參數 由於某些 DBMS 的限制,為了實現最大的可移植性,建議先檢索由執行CallableStatement 對象所產生的結果,然後再用 CallableStatement.getXXX 方法來檢索 OUT 參數。如果 CallableStatement 對象返回多個 ResultSet 對象(通過調用 execute 方法),在檢索 OUT 參數前應先檢索所有的結果。這種情況下,為確保對所有的結果都進行了訪問,必須對 Statement 方法 getResultSet、getUpdateCount 和getMoreResults 進行調用,直到不再有結果為止。 檢索完所有的結果後,就可用 CallableStatement.getXXX 方法來檢索 OUT 參數中的值。 5、檢索作為OUT參數的NULL值 返回到 OUT 參數中的值可能會是JDBC NULL。當出現這種情形時,將對 JDBC NULL 值進行轉換以使 getXXX 方法所返回的值為 null、0 或 false,這取決於getXXX 方法類型。對於 ResultSet 對象,要知道0或false是否源於JDBCNULL的唯一方法,是用方法wasNull進行檢測。如果 getXXX 方法讀取的最後一個值是 JDBC NULL,則該方法返回 true,否則返回 flase。
復雜的返回值 關於存儲過程的知識,很多人好像就熟悉我們所討論的這些。如果這是存儲過程的全部功能,那麼存儲過程就不是其它遠程執行機制的替換方案了。存儲過程的功能比這強大得多。
某些DBMS允許從存儲過程中返回遊標的一個引用。JDBC並不支持這個功能,但是Oracle、PostgreSQL和DB2的JDBC驅動器都支持在ResultSet上打開到游標的指針(pointer)。
設想列出所有沒有活到退休年齡的詩人,下面是完成這個功能的存儲過程,返回一個打開的游標,同樣也使用PostgreSQL的pl/pgsql語言: create procere list_early_deaths () return refcursor as 'declare toesup refcursor;begin open toesup for SELECT poets.name, deaths.age FROM poets, deaths -- all entries in deaths are for poets. -- but the table might become generic. WHERE poets.id = deaths.mort_id AND deaths.age < 60; return toesup;end;' language 'plpgsql'; 下面是調用該存儲過程的Java方法,將結果輸出到PrintWriter:
PrintWriter: static void sendEarlyDeaths(PrintWriter out){ Connection con = null; CallableStatement toesUp = null; try { con = ConnectionPool.getConnection(); // PostgreSQL needs a transaction to do this... con. setAutoCommit(false); // Setup the call. CallableStatement toesUp = connection.prepareCall("{ ? = call list_early_deaths () }"); toesUp.registerOutParameter(1, Types.OTHER); toesUp.execute(); ResultSet rs = (ResultSet) toesUp.getObject(1); while (rs.next()) { String name = rs.getString(1); int age = rs.getInt(2); out.println(name + " was " + age + " years old."); } rs.close(); } catch (SQLException e) { // We should protect these calls. toesUp.close(); con.close(); }} 因為JDBC並不直接支持從存儲過程中返回遊標,我們使用Types.OTHER來指示存儲過程的返回類型,然後調用getObject()方法並對返回值進行強制類型轉換。
這個調用存儲過程的Java方法是mapping的一個好例子。Mapping是對一個集上的操作進行抽象的方法。不是在這個過程上返回一個集,我們可以把操作傳送進去執行。本例中,操作就是把ResultSet列印到一個輸出流。這是一個值得舉例的很常用的例子,下面是調用同一個存儲過程的另外一個方法實現: public class ProcessPoetDeaths{ public abstract void sendDeath(String name, int age);} static void mapEarlyDeaths(ProcessPoetDeaths mapper){ Connection con = null; CallableStatement toesUp = null; try { con = ConnectionPool.getConnection(); con.setAutoCommit(false); CallableStatement toesUp = connection.prepareCall("{ ? = call list_early_deaths () }"); toesUp.registerOutParameter(1, Types.OTHER); toesUp.execute(); ResultSet rs = (ResultSet) toesUp.getObject(1); while (rs.next()) { String name = rs.getString(1); int age = rs.getInt(2); mapper.sendDeath(name, age); } rs.close(); } catch (SQLException e) { // We should protect these calls. toesUp.close(); con.close(); }} 這允許在ResultSet數據上執行任意的處理,而不需要改變或者復制獲取ResultSet的方法: static void sendEarlyDeaths(final PrintWriter out){ ProcessPoetDeaths myMapper = new ProcessPoetDeaths() { public void sendDeath(String name, int age) { out.println(name + " was " + age + " years old."); } }; mapEarlyDeaths(myMapper);} 這個方法使用ProcessPoetDeaths的一個匿名實例調用mapEarlyDeaths。該實例擁有sendDeath方法的一個實現,和我們上面的例子一樣的方式把結果寫入到輸出流。當然,這個技巧並不是存儲過程特有的,但是和存儲過程中返回的ResultSet結合使用,是一個非常強大的工具。 結論存儲過程可以幫助你在代碼中分離邏輯,這基本上總是有益的。這個分離的好處有:
快速創建應用,使用和應用一起改變和改善的資料庫模式。
資料庫模式可以在以後改變而不影響Java對象,當我們完成應用後,可以重新設計更好的模式。
存儲過程通過更好的SQL嵌入使得復雜的SQL更容易理解。
編寫存儲過程比在Java中編寫嵌入的SQL擁有更好的工具--大部分編輯器都提供語法高亮!
存儲過程可以在任何SQL命令行中測試,這使得調試更加容易。 並不是所有的資料庫都支持存儲過程,但是存在許多很棒的實現,包括免費/開源的和非免費的,所以移植並不是一個問題。Oracle、PostgreSQL和DB2都有類似的存儲過程語言,並且有在線的社區很好地支持。
存儲過程工具很多,有像TOAD或TORA這樣的編輯器、調試器和IDE,提供了編寫、維護PL/SQL或pl/pgsql的強大的環境。
存儲過程確實增加了你的代碼的開銷,但是它們和大多數的應用伺服器相比,開銷小得多。
⑻ java中怎麼用存儲過程啊
對已儲存過程的調用是CallableStatement對象所含的內容。這種調用是用一種換碼語法來寫的,有兩種形式:一種形式帶結果參,另一種形式不帶結果參數。結果參數是一種輸出(OUT)參數,是已儲存過程的返回值。兩種形式都可帶有數量可變的輸入(IN參數)、輸出(OUT參數)或輸入和輸出(INOUT參數)的參數。問號將用作參數的佔位符。在JDBC中調用已儲存過程的語法如下所示。注意,方括弧表示其間的內容是可選項;方括弧本身並非語法的組成部份。 {call過程名[(?,?,...)]} 返回結果參數的過程的語法為: {?=call過程名[(?,?,...)]} 不帶參數的已儲存過程的語法類似: {call過程名} 通常,創建CallableStatement對象的人應當知道所用的DBMS是支持已儲存過程的,並且知道這些過程都是些什麼。然而,如果需要檢查,多種DatabaseMetaData方法都可以提供這樣的信息。例如,如果DBMS支持已儲存過程的調用,則supportsStoredProceres方法將返回true,而getProceres方法將返回對已儲存過程的描述。 CallableStatement繼承Statement的方法(它們用於處理一般的SQL語句),還繼承了PreparedStatement的方法(它們用於處理IN參)。 CallableStatement中定義的所有方法都用於處理OUT參數或INOUT參數的輸出部分:注冊OUT參數的JDBC類型(一般SQL類型)、從這些參數中檢索結果,或者檢查所返回的值是否為JDBCNULL。 JDBC存儲過程1、創建CallableStatement對象 CallableStatement對象是用Connection方法prepareCall創建的。下例創建CallableStatement的實例,其中含有對已儲存過程getTestData調用。該過程有兩個變數,但不含結果參數:CallableStatementc stmt=con.prepareCall("{callgetTestData(?,?)}");其中?佔位符為IN、OUT還是INOUT參數,取決於已儲存過程getTestData。 JDBC存儲過程2、IN和OUT參數 將IN參數傳給CallableStatement對象是通過setXXX方法完成的。該方法繼承自PreparedStatement。所傳入參數的類型決定了所用的setXXX方法(例如,用setFloat來傳入float值等)。如果已儲存過程返回OUT參數,則在執行CallableStatement對象以前必須先注冊每個OUT參數的JDBC類型(這是必需的,因為某些DBMS要求JDBC類型)。注冊JDBC類型是用registerOutParameter方法來完成的。語句執行完後,CallableStatement的getXXX方法將取回參數值。正確的getXXX方法是為各參數所注冊的JDBC類型所對應的Java類型。換言之,registerOutParameter使用的是JDBC類型(因此它與資料庫返回的JDBC類型匹配),而getXXX將之轉換為Java類型。 作為示例,下述代碼先注冊OUT參數,執行由cstmt所調用的已儲存過程,然後檢索在OUT參數中返回的值。方法getByte從第一個OUT參數中取出一個Java位元組,而getBigDecimal從第二個OUT參數中取出一個BigDecimal對象(小數點後面帶三位數): CallableStatementc stmt=con.prepareCall("{callgetTestData(?,?)}"); cstmt.registerOutParameter(1,java.sql.Types.TINYINT); cstmt.registerOutParameter(2,java.sql.Types.DECIMAL,3); cstmt.executeQuery(); byte x=cstmt.getByte(1); java.math.BigDecimaln=cstmt.getBigDecimal(2,3); CallableStatement與ResultSet不同,它不提供用增量方式檢索大OUT值的特殊機制。JDBC存儲過程3、INOUT參數 既支持輸入又接受輸出的參數(INOUT參數)除了調用registerOutParameter方法外,還要求調用適當的setXXX方法(該方法是從PreparedStatement繼承來的)。setXXX方法將參數值設置為輸入參數,而registerOutParameter方法將它的JDBC類型注冊為輸出參數。setXXX方法提供一個Java值,而驅動程序先把這個值轉換為JDBC值,然後將它送到資料庫中。這種IN值的JDBC類型和提供給registerOutParameter方法的JDBC類型應該相同。然後,要檢索輸出值,就要用對應的getXXX方法。例如,Java類型為byte的參數應該使用方法setByte來賦輸入值。應該給registerOutParameter提供類型為TINYINT的JDBC類型,同時應使用getByte來檢索輸出值。 下例假設有一個已儲存過程reviseTotal,其唯一參數是INOUT參數。方法setByte把此參數設為25,驅動程序將把它作為JDBCTINYINT類型送到資料庫中。接著,registerOutParameter將該參數注冊為JDBCTINYINT。執行完該已儲存過程後,將返回一個新的JDBCTINYINT值。方法getByte將把這個新值作為Javabyte類型檢索。 CallableStatementc stmt=con.prepareCall("{callreviseTotal(?)}"); cstmt.setByte(1,25); cstmt.registerOutParameter(1,java.sql.Types.TINYINT); cstmt.executeUpdate(); byte x=cstmt.getByte(1); 1)返回一個結果集(ResultSet)。2)返回一個特定的值。下面來詳細的說明。1)返回一個結果集(ResultSet),這種類似通常的處理結果集如果事先就有一個類似如下的procere CREATE PROCEDURE getShipQuantity @jsid int ASSELECT jf_js_id,SUM(jf_ship_quantity) AS shipqty FROM tjobsheet_finish f WHERE (jf_js_id=@jsid)GROUP BY jf_js_id 那麼我們將通過如下的代碼來調用 String sql = "{ call getShipQuantity(?) }";Connection con = conn.connection();ResultSet rs = null;BigDecimal shipQuantity = new BigDecimal(0);try{ CallableStatement cs = con.prepareCall(sql); cs.setInt(1,jsoId);//設置輸入參數 rs = cs.executeQuery();//返回結果集 if(rs.next()){ shipQuantity = new BigDecimal(rs.getDouble(2)); } logger.debug("shipQuantity --------------------- "+shipQuantity);}catch(Exception e){ logger.debug(e);}2)返回一個特定的值。也就是說,在procere的定義中已經用output輸出參數了。請看下面的proceercreate procere getSingleWgt @@singleWgt numeric(8,3) output,@jsnum varchar(11) = '0000-0480'asdeclare @stwgt numeric(8,3)select @stwgt = sum(b.stwgt)from js as ainner join jsactdtl as b on a.jsnum = b.jsnumwhere a.completion = 1 and b.stflag = 22and a.jsnum = @jsnumselect @@singleWgt = (@stwgt/orderedqty) from js where jsnum = @jsnum那麼我們將通過如下的代碼來調用String sql = "{ call getSingleWgt(?,?) }";Connection con = getSession().connection();//得到connectiontry{ CallableStatement cs = con.prepareCall(sql);//通過它來執行sql cs.registerOutParameter(1,java.sql.Types.FLOAT);//注冊輸出參數 cs.setString(2,shipment.getJsnum());//指出輸入參數 if(cs.execute()){//執行 float output = cs.getFloat(1);//返回值 }}catch(Exception e){logger.debug(e);}