「MySQL」「觸發器,存儲過程和函數」

颯颯秋風 發佈 2020-01-16T19:40:45+00:00

如下:會報如下錯誤:insertinto person values Error Code: 1442. Can't update table 'person' in stored function/trigger because it is already used by st

1.原文地址

http://www.lgygg.wang/lgyblog/2019/11/13/mysql%e8%a7%a6%e5%8f%91%e5%99%a8%e5%ad%98%e5%82%a8%e8%bf%87%e7%a8%8b%e5%92%8c%e5%87%bd%e6%95%b0/

2.觸發器

1)觸發器概念

監視某種情況,並觸發某種操作,它是提供給程式設計師和數據分析員來保證數據完整性的一種方法,它是與表事件相關的特殊的存儲過程,它的執行不是由程序調用,也不是手工啟動,而是由事件來觸發,例如當對一個表進行操作( insert,delete, update)時就會激活它執行。

2)觸發器的使用

語法:

create trigger觸發器名字 
before|after 
insert|update|delete
on
被創建的表名字
For 觸發器的執行間隔
觸發器的sql語句

下圖是對語法的分析:

注意:
在MySQL中,默認以分號為分隔符,在寫存儲過程、存儲函數、觸發器時,編譯器會當做SQL語句來進行處理,編譯過程會出現錯誤,所以要事先用」delimiter @」聲明@(或者其他,由用戶自己定義)為當前的段分隔符,讓編譯器把兩個@之間的內容當做存儲過程、存儲函數、觸發器的代碼,在寫完整個內容完之後再」delimiter ;」將分隔符還原。

下面通過例子來介紹觸發器的使用,這是在MySQL中進行的,現在有兩張表person和person2
Person表的數據如下:

Person2表的數據如下:

當對person表執行插入操作的時候,將插入的name欄位改為「ttt」。如下兩個操作,觸發時間分別是after和before,但是結果是不一樣的。觸發器創建好之後,我執行如下插入語句

insert into person values(10,'ktv8','f',10);


name被修改為ttt,

這個結果,name沒有被修改為ttt,這是因為在插入數值的時候,數據已經被插入到資料庫里了,這時候是無法通過 set new.name=』ttt』修改name的值的。因為set new.name=』ttt』並不是一個更新的操作。
那麼如果我將觸發器的sql語句「set new.name=』ttt』」改為更新語句,那麼能不能實現更新?如下:

會報如下錯誤:

insert into person values(14,'ktv8','f',10) Error Code: 1442. Can't update table 'person' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.    0.031 sec

說明觸發器里,觸發的sql語句里的操作表不能和觸發表一樣,否則會報錯。
正常的使用情況是,當一張表發生了改變,觸發了觸發器,修改另一張表,如下操作:

3)觸發器其他語句

查看所有的觸發器:show triggers;
刪除觸發器:drop trigger 觸發器名字;

4)何時使用觸發器

一般情況下,Web應用的瓶頸常在DB上,所以會儘可能的減少DB做的事情,把耗時的服務做成Scale Out,這種情況下,肯定不會使用存儲過程;而如果只是一般的應用,DB沒有性能上的問題,在適當的場景下,也可以使用存儲過程。且如果觸發器位於資料庫里,不便於調試。
總的來說,觸發器我們很少用到,對於Web應用更是很少使用觸發器,因為不方便調試,很難定位觸發器引起的問題。

3.存儲過程

1)什麼是存儲過程

存儲過程(Stored Procedure)是在大型資料庫系統中,一組為了完成特定功能的SQL 語句集,它存儲在資料庫中,一次編譯後永久有效,用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是資料庫中的一個重要對象。

2)存儲過程的使用

create procedure 過程名([in|out|inout] 參數名 數據類型,…)
過程體

過程體以begin開頭,end結尾。
[in|out|inout]
IN 輸入參數:表示調用者向過程傳入值(傳入值可以是字面量或變量)
OUT 輸出參數:表示過程向調用者傳出值(可以返回多個值)(傳出值只能是變量)
INOUT 輸入輸出參數:既表示調用者向過程傳入值,又表示過程向調用者傳出值(值只能是變量)
Declare
用於聲明變量
declare 變量名 類型(長度) default 默認值;
Set
用於變量賦值。

下面通過一個例子來介紹存儲過程,這個存儲過程的功能是計算兩個整數相加的結果,如果兩個整數都是零,那麼就輸出存儲過程里a+b的結果。存儲過程如下,這是在MySQL中進行的:

如圖,兩個輸入參數為x和y,輸出結果通過result來傳達。
在過程體中,通過declare聲明了a,b和c三個參數,a默認值為5,b默認值為6,c默認值為0,但是通過set c=a+b,給c賦值,很明顯,c=11。
然後就是判斷了,當x和y都小於等於0的時候,將c賦值給result。當x和y都大於零的時候,result=x+y。
執行完上面創建存儲過程的語句之後,我們就要調用並輸出這個存儲過程的輸出結果。如下:

結果:

下面介紹存儲過程的其他操作語句:

列出存儲過程的詳細列表:show procedure status;
刪除:drop procedure 要刪除的存儲過程的名字;
查看創建存儲過程的信息:show create procedure 創建的存儲過程名字;
調用存儲過程:call 存儲過程名

3)何時使用存儲過程

觸發器和存儲過程只有在並發不高的項目,管理系統中使用。如果是面向用戶的高並發應用,都不要使用。
觸發器和存儲過程本身難以開發和維護,不能高效移植。觸發器完全可以用事務替代。存儲過程可以用後端腳本替代。
複雜的業務邏輯。沒辦法應用緩存。

4.存儲函數

語法:

CREATE FUNCTION 創建的存儲函數名字(參數名稱 參數類型,...,...)  
RETURNS 返回值得類型  
函數體;

使用:

調用存儲函數:select 函數名字([參數]); //根據定義函數的形參,形參與實參保持一致
查看創建函數信息:show create function 函數名字;
查看所有自定義函數:show function status;
刪除存儲函數:drop function 函數名字;

下面通過例子來介紹函數,該例子和上面存儲過程一樣,同樣是輸出x+y的值。代碼如下:

調用這個函數,

結果如下:

注意:
不能用於臨時表,只能用於永久表。

5.參考文章

觸發器:
https://blog.csdn.net/qq_36396104/article/details/80469997
https://blog.csdn.net/zhuoya_/article/details/81320471
存儲過程:
https://blog.csdn.net/me_to_007/article/details/90512433#_73
https://www.cnblogs.com/yuanwanli/p/9022617.html

關鍵字: