oracle as 不可以省略,Oracle:存储过程,存储函数
什么是存儲過程和存儲函數(shù):指存儲在數(shù)據(jù)庫中供所有用戶程序調(diào)用的子程序叫做存儲過程、存儲函數(shù)。
這個子程序是用PL/SQL寫的??梢杂肑ava程序調(diào)用,就是完成特定功能的子程序。
用create procedure命令創(chuàng)建存儲過程。
語法:
Create [or replace] procedure 過程名(參數(shù)列表) asPLSQL子程序體;
As相當(dāng)于declare,所以我們可以在as后面定義變量。As不可以省略。
--打印Hello World。
Create or replace procedure sayHelloWorld
As
--說明部分
Begin
Dbms_output.put_line(‘HelloWorld’);
End;
/
先將存儲過程編譯,在SQL Developer左邊的樹結(jié)構(gòu)中的過程里就產(chǎn)生了這個存儲過程。
如果圖標上有小紅叉,表示有語法錯誤,如果是綠葉,表示沒有問題。這個存儲過程的功能是打印HelloWorld。
如何調(diào)用這個存儲過程呢?
第一種方式:使用execute命令
Exec sayHelloWorld();
第二種調(diào)用方式:
Begin
sayHelloWorld();
sayHelloWorld();
sayHelloWorld();
end;
/
帶參數(shù)的存儲過程:
--給指定員工的工資漲100元工資,并且打印漲前和漲后的薪水。
--既然是指定,就是員工會變化,所以要接收一個員工參數(shù)。
--指定參數(shù)的時候要分為輸入?yún)?shù)和輸出參數(shù),默認是輸入?yún)?shù),但是顯示指出比較好,用in指出。
Create or replace procedure raiseSalary(enoin number)
As
--變量
Psalemp.sal%type;
Begin
--得到漲前的薪水。
Selectsal into psal from emp where empno = eno;
--漲100元
Updateemp set sal = sal + 100 where empno = eno;
--這里不要提交事務(wù),誰調(diào)用誰來提交事務(wù)
--打印漲前和漲后的薪水。
Dbms_output.put_line(‘漲前:’||psal||’漲后’||(psal+100));
End;
/
編譯。
調(diào)用:
Begin
raiseSalary(7839);
raiseSalary(7566);
commit;
end;
/
存儲過程和存儲函數(shù)的區(qū)別:
存儲過程沒有返回值,存儲函數(shù)可以有一個返回值。
存儲函數(shù):
函數(shù)為一命名的存儲程序,可以帶參數(shù),并返回一個計算值。函數(shù)和過程的結(jié)構(gòu)類似,但必須有一個return子句,用于返回函數(shù)值。函數(shù)說明要指定函數(shù)名、結(jié)果值的類型,以及參數(shù)類型等。
語法:
Create [or replace] function 函數(shù)名(參數(shù)列表)
Return 函數(shù)值類型
As
PLSQL子程序體;
--查詢某個員工的年收入,通過函數(shù)查詢,查詢完將查詢結(jié)果返回。
--接收一個員工參數(shù)
Create or replace functionqueryEmpIncome(eno in number)
Return number
As
--年收入與月薪和獎金有關(guān),定義兩個變量,接收月薪和獎金。
Psalemp.sal%type;
Pcommemp.comm%type;
Begin
--得到該員工的月薪和獎金
Selectsal,comm into psal,pcomm from emp where empno = eno;
--返回年收入
Returnpsal*12+nvl(pcomm,0);
End;
/
編譯一下,在左邊的樹結(jié)構(gòu)中就出現(xiàn)了函數(shù)的部分。
直接在圖標上點右鍵選擇運行就可以運行。
打開對話框,傳參數(shù):
控制臺結(jié)果:
雙擊函數(shù),可以打開一個窗口,這個窗口有debug的功能,在側(cè)邊雙擊可以打斷點。
Debug需要權(quán)限,需要授權(quán)。
Grant DEBUG CONNECT SESSION , DEBUG ANY PROCEDUREto scott;
關(guān)于輸出參數(shù):
存儲過程和存儲函數(shù)都可以通過out指定一個或多個輸出參數(shù)。我們可以利用out參數(shù),在過程和函數(shù)中實現(xiàn)返回多個值。
原則:如果只有一個返回值,用存儲函數(shù),否則,就用存儲過程。
--out參數(shù)的例子。查詢并返回某個員工的姓名 月薪 職位
--因為要返回姓名,月薪,職位,就要在參數(shù)中定義為輸出參數(shù)。
Create or replace procedurequeryEmpInfo(eno in number,pename out varchar2,psal out number,pjob outvarchar2)
As
Begin
Selectename,sal,empjob into pename,psal,pjob from emp where empno = eno;
End;
/
編譯,在過程上刷新,右鍵運行。
如何在Java程序中調(diào)用存儲過程或存儲函數(shù)呢?
先獲取Connection,在獲取CallableStatement(Statement的子類)。
通過Connection的prepareCall(String sql)方法創(chuàng)建CallableStatement。
CallableStatement是用來執(zhí)行SQL存儲過程的接口。JDBCAPI提供了一個存儲過程SQL轉(zhuǎn)義語法,該語法允許對所有RDBMS使用標準方式調(diào)用存儲過程。
調(diào)用的SQL語法:
調(diào)存儲函數(shù):?=call[(,,…)]
掉存儲過程:call[(,…)]
調(diào)用示例:用PL/SQL比直接使用SQL調(diào)用效率要高。
創(chuàng)建工程,導(dǎo)入Oracle的jar包。Jar包位置如地址欄所示。
(1)JDBC工具類
Public class JDBCUtils {
Private static String driver = “oracle.jdbc.OracleDriver”;
Private static String url = “jdbc:oracle:thin:@localhost:1521:orcl”;
Private static String user = “scott”;
Private static String password = “tiger”;
Static {
Try{
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
Public static Connection getConnection() {
Try{
Return DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
e.printStackTrace();
}
Return null;
}
Public static void release(Connection conn,Statement st, ResultSet rs) {
If(rs != null) {
Try{
Rs.close();
} catch(SQLException e) {
e.printStackTrace();
} finally {
Rs = null; //為是么置null呢?需要垃圾回收,gc機制。
}
}
If(st != null) {
Try{
st.close();
} catch(SQLException e) {
e.printStackTrace();
} finally {
st = null;
}
}
If(conn != null) {
Try{
conn.close();
} catch(SQLException e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
}
Public class TestOracle {
@Test
Public void testProcedure() {
//第一個是輸入?yún)?shù),后三個是輸出參數(shù)。
String sql = “{call queryEmpInfo(?,?,?,?)}”;
Connection conn = null;
CallableStatement call = null;
Try {
Conn = JDBCUtils.getConnection();
Call = conn.prepareCall(sal);
//對于in參數(shù)賦值
Call.setInt(1,7839);
//對于out參數(shù)。在執(zhí)行后才有值。通過OracleTypes中的常量可以將Oracle的類型轉(zhuǎn)換成Java的類型
Call.registerOutParameter(2,OracleTypes.VARCHAR);
Call.registerOutParameter(3,OracleTypes.NUMBER);
Call.registerOutParameter(4,OracleTypes.VARCHAR);
//執(zhí)行
Call.execute();
//取出結(jié)果。
String name = call.getString(2);
double sal = call.getDouble(3);
String job = call.getString(4);
System.out.println(name);
System.out.println(sal);
System.out.println(job);
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(conn,call,null);
}
}
@Test
Public void testFunction(){
String sql = “{?=call queryEmpIncone(?)}”;
Connection conn = null;
CallableStatement call = null;
Try {
Conn = JDBCUtils.getConnection();
Call = conn.prepareCall(sal);
//第一個參數(shù)是返回值,先處理out參數(shù)
//對于out參數(shù)。在執(zhí)行后才有值。通過OracleTypes中的常量可以將Oracle的類型轉(zhuǎn)換成Java的類型
Call.registerOutParameter(1,OracleTypes.NUMBER);
//對于in參數(shù)賦值
Call.setInt(2,7839);
//執(zhí)行
Call.execute();
//取出結(jié)果。
double income = call.getDouble(1);
System.out.println(income);
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(conn,call,null);
}
}
}
--返回某個部門的所有員工的所有信息。這樣out就太多了
--可以通過在光標中定義。
在out中使用光標,有一個要求,必須將光標和存儲過程或者存儲函數(shù)放到一個包里面。
什么是包?
是一個數(shù)據(jù)庫對象,是包頭,包頭只負責(zé)聲明,包體只負責(zé)實現(xiàn)。
聲明包:
--例:根據(jù)員工的員工號查詢員工信息,要求返回員工的所有信息。
Create or replace package MYPACKAGE as
--自定義一個類型empcursor,這個類型引用cursor光標類型,也就是說,設(shè)個empcursor類型就是一個光標
Type empcursoris ref cursor;
--在out中使用自定義的光標類型
Procedurequeryemp(eid in number,empinfo out empcursor);
End MYPACKAGE;
什么是包體?
也是一個數(shù)據(jù)庫對象,包體要實現(xiàn)存儲過程和存儲函數(shù)。
CREATE OR REPLACE
PACKAGE BODY MYPACKAGE AS
PROCEDUREqueryemp(eid in number,empinfo out empcursor) AS
BEGIN
Openempinfo for select * fro emp where empno = eid;
ENDqueryemp;
END MYPACKAGE;
--返回某個部門的所有員工的所有信息
CREATE OR REPLACE
PACKAGE MYPACKAGE AS
Typeempcursor is ref cursor;
ProcedurequeryEmpList(dno in number,empList out empcursor);
END MYPACKAGE;
--編譯好后,在左邊的樹結(jié)構(gòu)中的程序包節(jié)點中就有了剛定義的包。右鍵,可以選擇創(chuàng)建包體。
--會將包頭中所有需要實現(xiàn)的程序都列出來。
CREATE OR REPLACE
PACKAGE BODY MYPACKAGE AS
ProcedurequeryEmpList(dno in number,empList out empcursor) AS
BEGIN
--這里open了光標,并沒有關(guān)閉光標,其實光標關(guān)閉了,
--因為在返回rs結(jié)果集后,程序關(guān)閉了rs,關(guān)閉了rs也就關(guān)閉了光標。
OpenempList for select * from emp where deptno = dno;
ENDqueryEmpList;
END MYPACKAGE;
//編寫測試程序
@Test
Public void testCursor() {
String sql = “{call MYPACKAGE.queryEmpList(?,?)}”;
Connection conn = null;
CallableStatement call = null;
ResultSet rs = null;
Try{
Conn = JDBCUtils.getConnection();
Call = conn.prepareCall(sql);
//對于in參數(shù)賦值。部門號
Call.setInt(1,10);
//對于out參數(shù),所有員工的所有信息。
Call.registerOutParameter(2,OracleTypes.CURSOR);
//執(zhí)行。
Call.execute();
//取出該部門中的員工的信息。Call中沒有g(shù)etCursor,需要轉(zhuǎn)成OracleCallableStatement
Rs = (OracleCallableStatement)call.getCursor(2);
While(rs.next()) {
String name = rs.getString(“ename”);
double sal = rs.getDouble(“sal”);
System.out.println(name + “ ” + sal);
}
} catch(Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.release(conn,call,rs);
}
}
上面的程序可以在MySQL中跑嗎?不可以,因為實現(xiàn)的是Oracle的接口。
總結(jié)
以上是生活随笔為你收集整理的oracle as 不可以省略,Oracle:存储过程,存储函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle 存储过程 输入,Oracl
- 下一篇: oracle+挂载dbf,dbf导入or