存儲過程、存儲函數和觸發器
- 存儲過程和存儲函數
定義:指存儲在數據庫中供所有用戶程序調用的子程序叫存儲過程或存儲函數。
區別:存儲函數可以同return number(類型)這種方式來返回一個值(且只能返回一個) - 觸發器
觸發器是一個與表相關聯的、存儲的PL/SQL程序 - 存儲過程、存儲函數和觸發器執行前都需要編譯(直接在pl/sql developer中執行程序)
存儲過程
-
存儲過程的用途及使用場景:
- 存儲過程只在創造時進行編譯,以后每次執行存儲過程都不需再重新編譯,
而一般 SQL 語句每執行一次就編譯一次,所以使用存儲過程可提高數據庫執行速度。 - 當對數據庫進行復雜操作時(如對多個表進行 Update,Insert,Query,Delete 時),
可將此復雜操作用存儲過程封裝起來與數據庫提供的事務處理結合一起使用。
這些操作,如果用程序來完成,就變成了一條條的 SQL 語句,可能要多次連接數據庫。
而換成存儲,只需要連接一次數據庫就可以了。 - 存儲過程可以重復使用,可減少數據庫開發人員的工作量。
- 安全性高,可設定只有某此用戶才具有對指定存儲過程的使用權
- 存儲過程只在創造時進行編譯,以后每次執行存儲過程都不需再重新編譯,
用CREATE PROCEDURE命令創建存儲過程
語法:
<pre>
create [or replace] procedure 過程名(參數列表)
AS
-- AS相當于PLSQL程序中的declare,AS關鍵字不可以省略,
declare可以在沒有聲明任何變量/cursor/exception時可以省略。
PLSQL子程序體
</pre>-
示例
調用方式:
1.execute sayHelloWorld();
2.begin
sayHelloWorld();
sayHelloWorld();
end;
-
PL/SQL Developer中調試存儲過程/存儲函數:
右鍵存儲過程 -> 添加調試信息(√) -> 測試
調試過程中可能出現以下錯誤
意思是當前賬號沒有調試權限,在命令窗口使用system登錄授權:grant DEBUG CONNECT SESSION , DEBUG ANY PROCEDURE to scott(當前賬號);
存儲函數
存儲過程和存儲函數中的IN/OUT
一般來講,過程和函數的區別在于函數可以有一個返回值,而過程沒有返回值。
但過程和函數都可以通過out指定一個或多個輸出參數。我們可以利用out參數在過程和函數中實現返回多個值。那么問題來了,存儲函數還有什么鳥用?其作用就是兼容低版本的Oracle。
<pre> 參數傳遞方式:IN,OUT,IN OUT
IN : 表示輸入參數,按值傳遞方式。
特點:它不允許在存儲過程中被重新賦值(相當于java中final修飾的參數)。
如果存儲過程的參數沒有指定參數傳遞類型,默認為IN
OUT : 表示輸出參數,可以理解為按引用傳遞方式。可以作為存儲過程的輸出結果,供外部調用者使用。
特點:當一個參數被指定為OUT類型時,就算在調用存儲過程之前對該參數進行了賦值,
在存儲過程中該參數的值仍然是null。
IN OUT : 即可作輸入參數,也可作輸出參數。
特點:是真正的按引用傳遞參數。即可作為傳入參數也可以作為傳出參數。
</pre>
存儲過程/存儲函數分別在什么時候用?
原則:如果只有一個返回值,用存儲函數,否則就用存儲過程。
-- 存儲過程返回多個值
-- 查詢某個員工的姓名,職位和月薪
create or replace procedure queryEmpInfo(eno in number,
pename out varchar2,
pjob out varchar2,
psal out number)
as
begin
select ename,empjob,sal into pename,pjob,psal from emp where empno = eno;
end;
觸發器
- 數據庫觸發器是一個與表相關聯的、存儲的PL/SQL程序。
每當一個特定的數據操作語句(insert,update,delete)在指定的表上發出時,
Oracle自動地執行觸發器中定義的語句序列。 - 觸發器的類型
- 語句級觸發器:在指定的操作語句之前或之后執行一次,不管這條語句響應了多少行。其實就是針對表
- 行級觸發器(FOR EACH ROW):觸發語句作用的每一條記錄都被觸發。其實就是針對表中的行。
在行級觸發器中使用:old和:new偽記錄變量識別值的狀態。 - 如何區分:就看程序中有沒有FOR EACH ROW這句代碼
- 觸發器的應用場景
- 數據確認
- 實施復雜的安全性檢查
- 做審計,跟蹤表上的所有的數據操作等
- 數據的備份和同步
- 查詢觸發器、存儲過程及存儲函數
- select * from user_triggers;
- select * from user_source;
- 語法
<pre>
CREATE [OR REPLACE] TRIGGER 觸發器名
{BEFORE | AFTER}
{INSERT | DELETE | UPDATE[OF 列名]}
ON 表名
[FOR EACH ROW [WHEN 條件]]
DECLARE
BEGIN
END;
-- []:表示可有可無,|:表示多個中可選一個
-- 注意:UPATE[OF 列名] 如果加上列名表示更新指定的列
</pre> - 示例