觸發器(Trigger)是 MySQL 中非常實用的一個功能,它可以在操作者對表進行「增刪改」 之前(或之后)被觸發,自動執行一段事先寫好的 SQL 代碼。
本教程帶領大家在實踐中學習,你將學到觸發器在實際應用場景中的重要應用。
在這個教程中客戶管理系統。在這套系統中,你需要設置在INSERT
表之前檢測操作者是否輸入錯誤數據、在 UPDATE
時,記錄操作者的行為 log ,以及在DELETE
時,判斷刪除的信息是否符合刪除規則。 這三類操作都可以使用 MySQL 觸發器來實現。
下面將詳細講解觸發器全部六種情況:
BEFORE INSERT
: 在插入數據前,檢測插入數據是否符合業務邏輯,如不符合返回錯誤信息。AFTER INSERT
: 在表 A 創建新賬戶后,將創建成功信息自動寫入表 B 中。BEFORE UPDATE
:在更新數據前,檢測更新數據是否符合業務邏輯,如不符合返回錯誤信息。AFTER UPDATE
:在更新數據后,將操作行為記錄在 log 中BEFORE DELETE
:在刪除數據前,檢查是否有關聯數據,如有,停止刪除操作。AFTER DELETE
:刪除表 A 信息后,自動刪除表 B 中與表 A 相關聯的信息。
先決條件
在開始之前,請確保您具備以下條件:
- 一台配置好的 Ubuntu 服務器,root 賬號。
- 服務器上配置好 MySQL Server
- MySQL root 賬號
創建示例數據庫
我們先創建一個干凈的示例數據庫,方便大家可以跟隨本教程一起實踐。我們會在這個數據庫中演示 MySQL 觸發器的多種工作方式。
首先,以 root 身份登錄到你的 MySQL 服務器:
mysql -u root -p
出現提示時,請輸入你 MySQL root 賬號的密碼,然后點擊 ENTER
繼續。看到 mysql>
提示后,運行以下命令,創建 demo_kalacloud
數據庫:
CREATE database demo_kalacloud;
輸出結果
Query OK, 1 row affected (0.00 sec)
接下來,切換到新建的 demo_kalacloud
數據庫:
USE demo_kalacloud;
輸出結果
Database changed
接着創建一個 customers
表。我們使用這個表記錄銀行客戶的信息。這個表包括 customer_id
,customer_name
,和level
。咱們先把客戶分為兩個級別:BASIC
和VIP
。
create table customers( customer_id BIGINT PRIMARY KEY, customer_name VARCHAR(50), level VARCHAR(50) ) ENGINE=INNODB;
輸出結果
Query OK, 0 rows affected (0.01 sec)
接着,我們向 customers
表中添加一些客戶記錄。
Insert into customers (customer_id, customer_name, level )values('1','Jack Ma','BASIC'); Insert into customers (customer_id, customer_name, level )values('2','Robin Li','BASIC'); Insert into customers (customer_id, customer_name, level )values('3','Pony Ma','VIP');
分別運行三個 INSERT
命令后,命令行輸出成功信息。
輸出結果
Query OK, 1 row affected (0.01 sec)
我們使用 SELECT
檢查一下三條信息是否已經寫入表中:
Select * from customers;
輸出結果
下面我們創建另一個表customer_status
,用於保存 customers
表中客戶的備注信息。
這個表包含 customer_id
和 status_notes
字段:
Create table customer_status(customer_id BIGINT PRIMARY KEY, status_notes VARCHAR(50)) ENGINE=INNODB;
然后,我們再創建一個 sales
表,這個表與 customer_id
關聯。保存與客戶有關的銷售數據。
Create table sales(sales_id BIGINT PRIMARY KEY, customer_id BIGINT, sales_amount DOUBLE ) ENGINE=INNODB;
輸出結果:
Query OK, 0 rows affected (0.01 sec)
最后一步,我們再建一個 audit_log
表,用來記錄操作員操作系統時的操作行為。方便管理員在發生問題時,有 log 可查。
Create table audit_log(log_id BIGINT PRIMARY KEY AUTO_INCREMENT, sales_id BIGINT, previous_amount DOUBLE, new_amount DOUBLE, updated_by VARCHAR(50), updated_on DATETIME ) ENGINE=INNODB;
輸出結果
Query OK, 0 rows affected (0.02 sec)
至此,已經把客戶管理系統表建立完成。接下來,我們將對這個管理系統的關鍵節點增加對應的觸發器。
1.BEFORE INSERT
觸發器使用方法
作為嚴謹的管理系統,對任何寫入系統的數據都應該提前檢測,以防止錯誤的信息被寫進去。
在寫入前檢測數據這個功能,我們可以使用BEFORE INSERT
觸發器來實現。
在操作者對 sales
表中的sales_amount
字段進行寫操作時,系統將在寫入(INSERT
)前檢查數據是否符合規范。
我們先來看一下,創建觸發器的基本語法。
DELIMITER // CREATE TRIGGER [觸發器的名字] [觸發器執行時機] [觸發器監測的對象] ON [表名] FOR EACH ROW [觸發器主體代碼]// DELIMITER ;
觸發器的結構包括:
DELIMITER //
:MySQL 默認分隔符是;
但在觸發器中,我們使用//
表示觸發器的開始與結束。[觸發器的名字]
:這里填寫觸發器的名字[觸發器執行時機]
:這里設置觸發器是在關鍵動作執行之前觸發,還是執行之后觸發。[觸發器監測的對象]
:觸發器可以監測INSERT
、UPDATE
、DELETE
的操作,當監測的命令對觸發器關聯的表進行操作時,觸發器就被激活了。[表名]
:將這個觸發器與數據庫中的表進行關聯,觸發器定義在表上,也附着在表上,如果這個表被刪除了,那么這個觸發器也隨之被刪除。FOR EACH ROW
:這句表示只要滿足觸發器觸發條件,觸發器都會被執行,也就是說帶上這個參數后,觸發器將監測每一行對關聯表操作的代碼,一旦符合條件,觸發器就會被觸發。[觸發器主體代碼]
:這里是當滿足觸發條件后,被觸發執行的代碼主體。這里可以是一句 SQL 語句,也可以是多行命令。如果是多行命令,那么這些命令要寫在BEGIN...END
之間。
注:在創建觸發器主體時,還可以使用OLD
和NEW
來獲取 SQL 執行INSERT
,UPDATE
和DELETE
操作前后的寫入數據。這里沒看明白沒關系,我們將會在接下來的實踐中,展開講解。
講到這里,大家看了一大堆雲里霧里的概念,如果沒看懂,也別擔心。接下來進入實踐環節,只要跟着貼代碼看返回結果,很快你就能夠通透理解觸發器了。
現在,我們來創建第一個觸發器,BEFORE INSERT
(在執行 insert
之前,執行觸發器)。這個觸發器用於監測操作者在寫入 sales
表中的 sales_amount
值時,這個值是否大於 10000
,如果大於,那么返回錯誤信息進行報錯。
登錄 MySQL Server 后,我們創建一個觸發器:
DELIMITER // CREATE TRIGGER validate_sales_amount BEFORE INSERT ON sales FOR EACH ROW IF NEW.sales_amount>10000 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = "你輸入的銷售總額超過 10000 元。"; END IF// DELIMITER ;
上面這段代碼中,我們使用IF...THEN...END IF
來創建一個監測 INSERT
語句寫入的值是否在限定的范圍內的觸發器。
這個觸發器的功能時監測 INSERT
在寫入sales_amount
值時,這個新增的(NEW
)值是否符合條件( > 10000
)。
當操作員錄入一個超過 10000 的數字,會返回如下錯誤信息:
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '你輸入的銷售總額超過 10000 元。';
我們來試試看,看看觸發器是否已啟用。
我們向 sales_amount
中插入一條 11000
的值。
Insert into sales(sales_id, customer_id, sales_amount) values('1','1','11000');
輸出結果
ERROR 1644 (45000): 你輸入的銷售總額超過 10000 元。
命令行返回錯誤信息,這就是我們剛剛創建觸發器時,填入的錯誤信息。與我們的設置一致。
下面我們 insert
一個值小於 10000
的數字:
Insert into sales(sales_id, customer_id, sales_amount) values('1','1','7700');
輸入值為 7700
小於設定的 10000
,insert
命令執行成功。
Output Query OK, 1 row affected (0.01 sec)
我們調出 sales
表,看看是否插入成功:
Select * from sales;
輸出確認數據在表中:
通過這張表,我們可以看到,7700 已經插入到表中。
剛剛我們演示了在執行 insert
命令前,檢測某個值是否符合設定,接着我們來看在執行 insert
之后,使用觸發器將不同的值保存到不同的表中。
- AFTER INSERT : 在表 A 創建新賬戶后,將創建成功信息自動寫入表 B 中。
- BEFORE UPDATE :在更新數據前,檢測更新數據是否符合業務邏輯,如不符合返回錯誤信息。
- AFTER UPDATE :在更新數據后,將操作行為記錄在 log 中
- BEFORE DELETE :在刪除數據前,檢查是否有關聯數據,如有,停止刪除操作。
- AFTER DELETE :刪除表 A 信息后,自動刪除表 B 中與表 A 相關聯的信息