1. 程式人生 > >從頭開始學MySQL-------觸發器

從頭開始學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;