1. 簡單的預存程序的建立:
1) 一個MySQL中典型的預存程序的建立:
delimitercreate procedure add(a int, b int, out sum int)beginset sum = a + b;end;
。。預存程序類似於C/Java中的函數和方法,具有參數傳入,但是沒有傳回值;
。。傳回值是通過輸出參數來擷取的,輸出參數之前要用out關鍵字限定,預存程序執行完畢後就可以從輸出參數中取出想要的計算結果;
。。具體的預存程序的有關知識在這裡就不詳解了;
2. JDBC執行預存程序:
1) 首先預存程序必須現在資料庫中寫好並編譯好,以供其它應用程式調用它,畢竟預存程序跟資料包、索引、視圖等都是資料庫物件,地位都是相同的,因此在應用程式中查詢一個表和調用一個預存程序的地位是相同;
2) 要調用一個預存程序就必須先擷取一個”調用預存程序的控制代碼“,它也是一種Statement,也可以通過Connection(conn)來擷取,就是CallableStatement;
3) 擷取CallableStatement:CallableStatement Connection.prepareCall(String sql);
i. 可以看到得到的調用控制代碼同樣是先行編譯好的,只要方法是prepare作為首碼的都表示先行編譯,而已create作為首碼的都表示是直接提交執行的(即每次提交都要編譯);
ii. 畢竟,預存程序是一種資料庫物件儲存在資料庫中,因此這裡唯一能提交的SQL語句也就是調用預存程序的語句了,因此這裡先行編譯的SQL語句必須是call語句;
iii. 調用預存程序的call語句文法格式是:{call 過程名(參數1, 參數2...)}; // 注意。外面一定要加花括弧
iv. 既然是先行編譯的那就允許使用預留位置,這是理所應當的,一般都是形參部分使用預留位置代替,後期用具體的參數填寫它;
v. 樣本(擷取一個先行編譯的調用預存程序的SQL語句):CallableStatement cstmt = conn.prepareCall("{call add(?, ?, ?)}");
4) 後期可以通過CallableStatement的setXxx方法來填寫預留位置,和PrepareStatement的setXxx一樣,只不過CallableStatement還提供了一個根據形參名填寫預留位置的重載版本:
i. void setXxx(int parameterIndex, Xxx x); // 正常版本
ii. void setXxx(String parameterName, Xxx x); // 根據參數名來填寫預留位置
。。因為預存程序定義中參數都是有名字的,就是根據這個名字來填寫預留位置;
5) 那該如何擷取輸出參數的值呢。
i. 在調用預存程序時傳入輸入參數的值是理所應當的(同時也是必須的),上面的setXxx方法就是傳入輸入參數的值;
ii. 而輸出參數也可以作為輸入參數,只不過輸入時當做輸入參數處理,當預存程序計算完之後會把結果覆蓋到輸出參數輸出罷了,因此輸出參數也可以用setXxx傳值;
iii. 但是一般符合規範的做法是不要給輸出參數傳至,即調用用JDBC調用預存程序時不要為輸出參數傳值(輸出參數最好是純當傳回值使用),而只在預存程序計算完畢之後再取出輸出參數的值;
iv. JDBC要求必須先給CallableStatement對象註冊輸出參數(即提前現高數CallableStatement誰是輸出參數,這樣好讓它先做好準備),使用registerOutParameter進行註冊:void CallableStatement.registerOutParameter(String parameterName | int parameterIndex, SQLType sqlType);
a. 該函數可以用參數名parameterName或者參數索引parameterIndex(從1開始)來定位誰是輸出參數;
b. SQLType是SQL的資料類型(即int、varchar、blob等),因此sqlType即使指該參數的類型應該是SQL資料類型裡的哪種;
c. 這裡SQLType只是一個抽象介面,實際中應該是用其實作類別Types(位於sql包中),其中定義了幾乎所有標準SQL支援的類型,例如INTERGER、DOUBLE、BLOB等;
d. 樣本:cstmt.registerOutParameter(3, Types.INTEGER); // 告訴cstmt第三個參數是輸出參數,其在SQL中的類型是int型的
v. 當執行完預存程序後就可以用getXxx方法擷取輸出參數的值了,getXxx和setXxx是相對應的,其也有兩個重載版本,一個是根據索引指定參數,另一個是根據參數名指定參數:Xxx CallableStatement.getXxx(int parameterIndex | String parameterName);
。。注意:一定要用該方法擷取輸出參數的值,不要擷取輸入參數的值。
6) 執行預存程序:直接調用CallableStatement的execute方法即可,既然是先行編譯的必然無參,而且也沒有其他版本(executeUpdate、executeQuery),因為CallableStatement就是專門用來調用預存程序的,因此就只有execute方法一種:boolean CallableStatement.execute();
3. 樣本:一個完整的執行預存程序的例子
CallableStatement cstmt = conn.prepareCall("{call add_pro(?, ?, ?)}"); // 建立一個先行編譯的預存程序調用SQL語句cstmt.setInt(1, 5); // 參數索引指定,第一個參數cstmt.setInt("b", 6); // 參數名指定cstmt.registerOutParameter(3, Types.INTEGER); // 註冊輸出參數以及其SQL類型cstmt.execute(); // 執行預存程序int ret = cstmt.getInt(3); // 計算完成後擷取輸出參數的值