1.存儲過程語法
Oracle存儲過程基本語法存儲過程
1 CREATE OR REPLACE PROCEDURE 存儲過程名
2 IS
3 BEGIN
4 NULL;
5 END;
行1:
CREATE OR REPLACE PROCEDURE 是一個SQL語句通知Oracle數據庫去創建一個叫做skeleton存儲過程, 如果存在就覆蓋它;
行2:
IS關鍵詞表明后面將跟隨一個PL/SQL體。
行3:
BEGIN關鍵詞表明PL/SQL體的開始。
行4:
NULL PL/SQL語句表明什么事都不做,這句不能刪去,因為PL/SQL體中至少需要有一句;
行5:
END關鍵詞表明PL/SQL體的結束
存儲過程創建語法:
create orreplace procedure 存儲過程名(param1 in type,param2 out type)
as
變量1 類型(值范圍);--vs_msg VARCHAR2(4000);
變量2 類型(值范圍);
Begin
Select count(*)into 變量1 from 表A where列名=param1;
If (判斷條件) then
Select 列名 into 變量2 from 表A where列名=param1;
Dbms_output。Put_line(‘打印信息');
Elsif (判斷條件) then
Dbms_output。Put_line(‘打印信息');
Else
Raise 異常名(NO_DATA_FOUND);
End if;
Exception
When others then
Rollback;
End;
例子2
create orreplace procedure EMP_PROCEDURE2(
eno number, --輸入參數,
name varchar2,
)
IS
emp_null_error EXCEPTION; --聲明異常變量
PRAGMA EXCEPTION_INIT(emp_null_error,-1400);--非預定義異常,前提:deptno列非空。插入空值會報錯
emp_no_deptno EXCEPTION; --聲明異常變量
PRAGMA EXCEPTION_INIT(emp_no_deptno, -2291);--非預定義異常,
begin
insert into emp(empno,ename,sal,deptno)values (eno,name,sal,dno);
exception
when DUP_VAL_oN_INDEX then
RAISE_APPLICATION_ERROR(-20000,'該雇員已存在');
when emp_null_error then
RAISE_APPLICATION_ERROR(-20001,'部門編號不能為空');
when emp_no_deptno then
RAISE_APPLICATION_ERROR(-20002,'不存在該部門編號');
end;
EXECUTEEMP_PROCEDURE2(1001,'榮世林',2000,10);
注意事項:
1, 存儲過程參數不帶取值范圍,in表示傳入,out表示輸出
類型可以使用任意Oracle中的合法類型。
2, 變量帶取值范圍,后面接分號
3, 在判斷語句前最好先用count(*)函數判斷是否存在該條操作記錄
4, 用select 。。。into。。。給變量賦值
5, 在代碼中拋異常用 raise+異常名
2.CallableStatement 執行存儲過程
概述
如果想要執行存儲過程,我們應該使用 CallableStatement 接口。
CallableStatement 接口繼承自 PreparedStatement 接口。所以 CallableStatement 接口
包含有 Statement 接口和 PreparedStatement 接口定義的全部方法,但是並不是所有的方法我
們都要使用,主要使用的方法有這樣幾個:
2.1常用方法
返回類型 |
方法簽名 |
說明 |
boolean |
execute() |
執行 SQL 語句,如果第一個結果是 ResultSet 對 象,則返回 true;如果第一個結果是更新計數或者沒 有結果,則返回 false |
void |
registerOutParameter (int parameterIndex, int sqlType) |
按順序位置 parameterIndex 將 OUT 參數注冊為 JDBC 類型 sqlType,sqlType 為 Types 類中的常量 |
Type |
getType(int parameterIndex) |
根據參數的序號獲取指定的 JDBC 參數的值。第一 個參數是 1,第二個參數是 2,依此類推 |
我們可以使用 execute()方法來執行存儲過程。CallableStatement 為所有的數據庫提供了
一種統一的標准形式調用存儲過程。所以,你將會看到我們使用 execute()調用存儲過程的語
法與在 Oracle 中會所有不同。
為了獲得存儲過程或函數的返回值,我們需要使用registerOutParameter()方法將返回的
參數注冊為 JDBC 的類型。 registerOutParameter()方法的第一個參數是參數的序號,第一個
為 1,第二個為 2,以此類推。第二個參數需要一個 int 值,用來標記 JDBC 的類型,我們可以
使用 java.sql.Types 類中的常量來設置這個參數。比如 VARCHAR、DOUBLE 等類型。如果類型不
夠用,也可以從具體數據庫的驅動中尋找合適的類型常量。如果存儲過程或函數有返回值,這
個方法是必須要調用的,否則無法得到返回值,甚至會發生異常。
CallableStatement 接口中定義了很多 get 方法,用於獲取存儲過程返回的值,根據值的
類型不同,你可以使用不同 get 方法,比如 getInt()、getString()、getDouble()等等。
我們看一下使用 CallableStatement 接口執行存儲過程和函數的語法格式。
存儲過程:{call<procedure-name>[(<arg1>,<arg2>, ...)]}
函數:{?= call<procedure-name>[(<arg1>,<arg2>, ...)]}
如果要調用存儲過程,則使用第一種語法,就是開頭不帶問號的語法,call 后面是過程名,
如果沒有參數,可以省略小括號。
如果要調用函數,則使用第二種語法,開頭帶有一個問號加等號,實際上這個問號就是一
個占位符,這個問號總是調用函數的第一個占位符。其它部分與過程的語法相同。
這樣說起來可能比較抽象,我們通過代碼來學習一下。
2.2執行存儲過程
(1) 執行不帶參但是有返回值的存儲過程
存儲過程代碼如下:
create or replaceprocedure getNewsCount(v_totalCount out number) as
begin
select count(*) intov_totalCount from news_detail;
end;
該 存 儲 過 程 為 查 詢 新 聞 明 細 表 (news_detail) 中新 聞 的 總 記 錄 數 , 並 將 結 果 存 儲 在
v_totalCount 中返回。執行該存儲過程的代碼如下:
//獲取新聞總數量(執行存儲過程)
public intgetTotalCountProc(){
int totalCount=0;
CallableStatementproc=null;
Stringsql="{call getNewsCount(?)}";
getConnection();
try {
proc=conn.prepareCall(sql);
proc.registerOutParameter(1,Types.INTEGER);
proc.execute();
totalCount=proc.getInt(1);
} catch (SQLExceptione) {
e.printStackTrace();
}
return totalCount;
}
(2) 執行帶參帶返回值的存儲過程
存儲過程代碼如下:
create or replaceprocedure getNewsCount(v_categoryId in number,v_title in varchar2,v_totalCount out number) as
begin
if (v_categoryId = 0)then
select count(*) intov_totalCount from news_detail
where title like'%'||v_title||'%';
else
select count(*) intov_totalCount from news_detail
where categoryId =v_categoryId
and title like'%'||v_title||'%';
end if;
end;
該存儲過程為根據新聞類別 ID(categoryId)以及新聞標題(title)查詢新聞明細表
(news_detail)中新聞的總記錄數,並將結果存儲在 v_totalCount 中返回。其中,新聞類別以
及新聞標題分別以輸入參數的形式傳入存儲過程。執行該存儲過程的代碼如下:
//根據新聞類別 ID 以及新聞標題獲取新聞總記錄數
public intgetTotalCount(int categoryId, String title) {
int iCount = 0;
CallableStatementproc = null;
try {
String sql ="{call getNewsCount(?,?,?)}";
getConnection();
proc =conn.prepareCall(sql);
proc.setInt(1,categoryId);
proc.setString(2,title);
proc.registerOutParameter(3,Types.INTEGER);
proc.execute();
iCount =proc.getInt(3);
} catch (Exception e){
e.printStackTrace();
}finally{
if (proc != null){
try {
proc.close();
} catch (SQLExceptione) {
e.printStackTrace();
}
}
closeResource();
}
return iCount;
}
(3) 執行返回值為游標的存儲過程
Employees 雇員表(name 雇員姓名;gender 雇員性別;borndate 雇員生日)
存儲過程代碼如下:
create or replaceprocedure find_emp3(emp_cursor out sys_refcursor) is
begin
open emp_cursor forselect name,gender,borndate from employees;
end find_emp3;
該存儲過程為查詢所有雇員姓名、性別、生日的存儲過程,結果以游標的形式返回。執行
該存儲過程的代碼如下:
String sql ="{call find_emp3(?)}";
Connection con =null;
CallableStatementcstmt = null;
ResultSet rs = null;
try {
Class.forName("oracle.jdbc.OracleDriver");
con = DriverManager 個.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl","pbdevj","pwd1234");
cstmt =con.prepareCall(sql);
cstmt.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);
cstmt.execute();
rs =(ResultSet)cstmt.getObject(1);
while (rs.next()) {
//省略
}
} catch { //省略 } finally { //省略 }
(4) 執行函數
函數代碼如下:
create or replacefunction find_emp2(emp_no number) return varchar2 is
empname varchar2(20);
|
begin
select name intoempname from employees where id=emp_no;
return empname;
exception
when no_data_foundthen
return '雇員編號未找到';
end find_emp2;
該函數功能為根據雇員 id 返回姓名。執行該函數的代碼如下:
String sql ="{?=call find_emp2(?)}";
Connection con =null;
CallableStatementcstmt = null;
try {
Class.forName("oracle.jdbc.OracleDriver");
con =DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl","pbdevj","pwd1234");
cstmt =con.prepareCall(sql);
cstmt.setInt(2, 1);
cstmt.registerOutParameter(1,Types.VARCHAR);
cstmt.execute();
System.out.println(cstmt.getString(1));
} catch { //省略 } finally { //省略 }