【Oracle基礎】存儲過程,存儲函數,觸發器,java調用存儲過程
1. 存儲過程
存儲過程(Stored Procedure)是在大型數據庫系統中,一組爲了完成特定功能的 SQL 語句集,經編譯後存儲在數據庫中,用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象,任何一個設計良好的數據庫應用程序都應該用到存儲過程。
簡單來說:存儲過程就是提前已經編譯好的一段pl/sql語言,放置在數據庫端,可以直接被調用。這一段pl/sql一般都是固定步驟的業務。
- 語法
create [or replace] PROCEDURE 過程名[(參數名 in/out 數據類型)]
AS
begin
PLSQL 子程序體;
End;
或者
create [or replace] PROCEDURE 過程名[(參數名 in/out 數據類型)]
is
begin
PLSQL 子程序體;
End 過程名;
- 示例
---給指定員工漲100塊錢
create or replace procedure p1(eno emp.empno%type)
as
begin
update emp set sal=sal+100 where empno=eno;
commit;
end;
- 調用
--測試pl
declare
begin
p1(7788);
end;
2. 存儲函數
- 語法
create or replace function 函數名(Name in type, Name in type, ...) return 數據類型 is
結果變量 數據類型;
begin
return(結果變量);
end 函數名;
- 存儲過程和存儲函數的區別
一般來講,過程和函數的區別在於函數可以有一個返回值;而過程沒有返回值。
但過程和函數都可以通過 out 指定一個或多個輸出參數。我們可以利用 out 參數,在過程和函數中實現返回多個值。
如果存儲過程想實現有返回值的業務,我們就必須使用out類型和參數。
即便是存儲過程使用了out類型的參數,其本質也不是真的有了返回值。
而是在存儲過程內部給out類型參數賦值,在執行完畢後,我們直接拿着用。
---通過存儲函數實現計算指定員工的年薪
---存儲過程和存儲函數的參數都不能帶長度
---存儲函數的返回值類型不能帶長度
create or replace function f_yearsal(eno emp.empno%type) return number
is
s number(10);
begin
select sal*12+nvl(comm,0) into s from emp where empno=eno;
return s;
end f_yearsal;
--測試f_yearsal
---存儲函數在調用的時候,返回值需要接收
declare
s number(10);
begin
s := f_yearsal(7788);
dbms_output.put_line(s);
end;
---out類型參數如何使用
---使用存儲過程來算年薪
create or replace procedure p_yearsal(eno emp.empno%type,yearsal out number)
is
s number(10);
c emp.comm%type;
begin
select sal*12,nvl(comm,0) into s,c from emp where empno=eno;
yearsal := s+c;
end;
---測試p_yearsal
declare
yearsal number(10);
begin
p_yearsal(7788,yearsal);
dbms_output.put_line(yearsal);
end;
--in和out類型的區別是什麼?
---凡是涉及到into查詢語句賦值或者:=賦值操作的參數,都必須使用out來修飾
3. 觸發器
數據庫觸發器是一個與表相關聯的、存儲的 PL/SQL 程序。每當一個特定的數據操作語句(Insert,update,delete)在指定的表上發出時, Oracle 自動地執行觸發器中定義的語句序列
- 觸發器可用於
- 數據確認
- 實施複雜的安全性檢查
- 做審計,跟蹤表上所做的數據操作等
- 數據的備份和同步
-
觸發器的類型
- 語句級觸發器 : 在指定的操作語句操作之前或之後執行一次,不管這條語句影響了多少行 。
- 行級觸發器(FOR EACH ROW) : 觸發語句作用的每一條記錄都被觸發。在行級觸發器中使用 old 和 new 僞記錄變量, 識別值的狀態。
-
語法
CREATE [or REPLACE] TRIGGER 觸發器名
{BEFORE | AFTER}
{DELETE | INSERT | UPDATE [OF 列名]}
ON 表名
[FOR EACH ROW [WHEN(條件) ] ]
begin
PLSQL 塊
End 觸發器名
---觸發器,就是指定一個規則,在我們做增刪改操作的時候,
-------只要滿足該規則,自動觸發,無需調用
-------語句級觸發器
-------行級觸發器:包含有for each row的就是行級觸發器。
-------------------加for each row是爲了使用:old或者:new對象或者一行記錄。
----插入一條記錄,輸出一個新員工入職
--語句級觸發器
create or replace trigger t1
after
insert
on person
declare
begin
dbms_output.put_line('一個新員工入職');
end;
---觸發t1
select * from person;
insert into person values(1,'小紅');
commit;
--行級觸發器
create or replace trigger t2
before
update
on emp
for each row
declare
begin
if :old.sal>:new.sal then
raise_application_error(-20001,'不能給員工降薪');
end if;
end;
--觸發t2
update emp set sal=sal-1 where empno=7788;
commit;
--觸發器實現主鍵自增
---分析:在用戶做插入操作的之前,拿到即將插入的數據,給該數據中的主鍵列賦值。
create or replace trigger auid
before
insert
on person
for each row
declare
begin
select s_person.nextval into :new.pid from dual;
end;
--使用autoid實現主鍵自增
insert into person(pname) values('a');
commit;
select * from person
4. java調用存儲過程
首先我們可以在虛擬機中oracle 安裝目錄下找到 jar 包 :ojdbc14.jar
當然也可以使用maven工程導入座標。
package com.siyi.oracle;
import oracle.jdbc.OracleTypes;
import oracle.jdbc.oracore.OracleType;
import org.junit.Test;
import java.sql.*;
public class OracleDemo {
@Test
public void javaCallOracle() throws ClassNotFoundException, SQLException {
//加載數據庫驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
//得到Connection連接
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.105:1521:orcl", "siyi", "siyi");
//得到預編譯的Statement對象
PreparedStatement ps = connection.prepareStatement("select * from emp where empno = ?");
ps.setObject(1,7788);
//執行數據庫查詢操作
ResultSet resultSet = ps.executeQuery();
//輸出結果
while(resultSet.next()){
System.out.println(resultSet.getString("ename"));
}
//釋放資源
resultSet.close();
ps.close();
connection.close();
}
/**
* java調用存儲過程
* @throws ClassNotFoundException
* @throws SQLException
*/
@Test
public void javaCallProcedure() throws ClassNotFoundException, SQLException {
//加載數據庫驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
//得到Connection連接
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.105:1521:orcl", "siyi", "siyi");
//得到預編譯的Statement對象
CallableStatement cs = connection.prepareCall("call p_yearsal(?,?)");
cs.setObject(1,7788);
cs.registerOutParameter(2, OracleTypes.NUMBER);
//執行數據庫查詢操作
cs.executeQuery();
//輸出結果
System.out.println(cs.getObject(2));
//釋放資源
cs.close();
connection.close();
}
/**
* java調用存儲函數
* @throws ClassNotFoundException
* @throws SQLException
*/
@Test
public void javaCallFunction() throws ClassNotFoundException, SQLException {
//加載數據庫驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
//得到Connection連接
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.105:1521:orcl", "siyi", "siyi");
//得到預編譯的Statement對象
CallableStatement cs = connection.prepareCall("{?= call f_yearsal(?)}");
cs.setObject(2,7788);
cs.registerOutParameter(1, OracleTypes.NUMBER);
//執行數據庫查詢操作
cs.executeQuery();
//輸出結果
System.out.println(cs.getObject(1));
//釋放資源
cs.close();
connection.close();
}
}