從頭開始學MySQL-------觸發器
12.1.1 建立觸發器
觸發器是由事件觸發的操作,這些事件包括INSERT、UPDATE、DELETE事件。觸發器是一種特殊的儲存過程,它預定義了一些SQL,不用CALL來呼叫。當指定的事件發生的時候,觸發器就會自動執行。
觸發器語法:
CREATE TRIGGER trigger_name trigger_time trigger_type ON table_name
FOR EACH ROW trigger_stmt
trigger_name 是觸發器的名字
trigger_time 取值為BEFORE和AFTER,表示觸發時機。
trigger_type 指觸發事件,包括INSERT UPDATE DELETE
trigger_stmt 可以編寫儲存過程,比如 SET @result = NEW.欄位。 NEW代表剛才更新或者插入的記錄。
觸發器用來滿足一些複雜的業務需要,比如根據客戶當前的賬戶狀態,判斷是否允許插入新的訂單。
-- 下面的觸發器定義的意思是: -- 在table_name表執行UPDATE操作之前,先往t_operation表中插入一條記錄,再執行更新的SQL CREATE TRIGGER trigger_name BEFORE UPDATE ON table_name FOR EACH ROW BEGIN INSERT INTO t_operation(..) VALUES(..); END
首先準備3張表,存錢記錄表t_take_in、取錢記錄表t_take_out與銀行餘額表t_bank。
現在需求:假設銀行餘額現在有500,即t_bank表中有一條記錄,金額屬性為500。如果往t_take_in表中插入一條記錄,意味著存了一筆錢。如果往取錢記錄表t_take_out表中插入一條記錄,意味著取了一筆錢。例如,往存錢記錄表t_take_in插入一條金額為100的記錄,即又存了100,那麼銀行餘額表t_bank的金額屬性應該為600。再往取錢記錄表t_take_out中插入一條金額為200的記錄,意味著取了200,那麼銀行餘額表t_bank的金額屬性應該剩餘400。
DROP TABLE IF EXISTS t_take_in;
CREATE TABLE t_take_in -- 存錢記錄表
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
money DECIMAL(5,2), -- 存入金額
inDate DATETIME DEFAULT NOW() -- 存入時間
);
DROP TABLE IF EXISTS t_take_out;
CREATE TABLE t_take_out -- 取錢記錄表
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
money DECIMAL(5,2), -- 支出金額
outDate DATETIME DEFAULT NOW() -- 支出時間
);
再建立一個賬戶表。我的打算是這樣的,假設賬戶表中已經有了一定的錢。向“存錢記錄表t_take_in”中存放錢,將會觸發餘額表的觸發器,讓它更新"銀行餘額表t_bank"。同樣,在"取錢記錄表t_take_out"中插入資料,意思是當前使用者取出了一筆錢,那麼也用觸發器,同步更新"銀行餘額表t_bank"。
DROP TABLE IF EXISTS t_bank;
CREATE TABLE t_bank
(
money DECIMAL(5,2)
);
INSERT INTO t_bank(money) VALUES(500);
下面開始建立觸發器。
DELIMITER //
CREATE TRIGGER addMoney AFTER INSERT ON t_take_in -- 為存錢表加入AFTER INSERT觸發器
FOR EACH ROW
BEGIN
UPDATE t_bank SET MONEY = MONEY + NEW.money; -- 存錢表存錢後觸發更新,NEW代表剛才更新或者插入的記錄。
END //
DELIMITER ;
DELIMITER //
CREATE TRIGGER useMoney AFTER INSERT ON t_take_out -- 在取錢記錄表上建立AFTER INSERT觸發器
FOR EACH ROW -- 即當t_take_out出現INSERT語句的時候,執行下面的SQL
BEGIN
UPDATE t_bank SET MONEY = MONEY - NEW.money; -- NEW代表剛才更新或者插入的記錄。
END //
DELIMITER ;
-- 現在向存錢表裡面存錢
INSERT INTO t_take_in(money) VALUES(100);
檢視各個表的情況。
存錢記錄表t_take_in表裡面多了剛才插入的記錄。
最關鍵的"賬戶表t_bank"的情況,我們來看看。從500變成了600,說明觸發器中的SQL執行了。
再來測試一下向"取錢記錄表t_take_out"中插入資料,即新增一筆取款記錄。
-- 現在向取錢表裡面取錢,取200塊,賬戶表預期剩餘600-200 = 400元
INSERT INTO t_take_out(money) VALUES(200);
取錢記錄表t_take_out表裡應該新增一條記錄。新增取款200塊。
賬戶表t_bank應該預期為400。
與預期一致,說明觸發器設定成功。
撥雲見日
原來觸發器也不是什麼神祕的東西,它是一種特殊的儲存過程,它預定義了一些SQL語句。當其它表發生增刪改事件的時候,它就會被觸發,執行預定義的SQL。
從設計模式的角度來看待,它其實就是一種觀察者設計模式。從Java的角度來看待,它就是一個監聽器。觸發器觸發後將會執行定義好的SQL語句。
12.1.2 檢視觸發器
所有的觸發器都存放在information_schema資料庫中的triggers表中。
SELECT * FROM information_schema.`TRIGGERS` WHERE TRIGGER_NAME LIKE '%Money%'
第二種方法就是最常用的方法:SHOW TRIGGERS;
SHOW TRIGGERS;
12.1.3 刪除觸發器
DROP TRIGGER IF EXISTS useMoney;
-- 補充刪除檢視的方法
DROP VIEW IF EXISTS view_name;
12.1.4 專家解惑
惑而不從師其為惑也終不解矣。
能不能建立兩個相同事件的觸發器?
比如能否在同一張表上建立兩個 BEFORE INSERT 觸發器?答案是不可以。此時,只可以在這張表上建立其它的觸發器,比如 AFTER INSERT,BEFORE UPDATE。
結論:相同事件只能建立一個觸發器。
表結構發生更改,觸發器會自動刪除嗎?
表結構發生更改,不會自動刪除觸發器,除非刪除了這張表,觸發器會自動被刪除。
如果因為需求的變化,舊的觸發器沒有被及時手動刪除的話,舊的觸發器將會照常工作,可能會影響資料完整性,因此需要手動刪除。DROP TRIGGER trigger_name;