觸發器(trigger)是數據庫中的一個很重要的、很實用的基於事件的處理器,在處理一些業務需求的時候,使用觸發器會很方便。彷佛在《高性能MySQL》中,對觸發器做了必定的描述,也提到使用中的一些優點和侷限性,但感受仍是不能徹底理解觸發器的所有功能和實現。因而本身在網上看了一些文章,結合官網(https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html)中的案例,寫下這篇總結。html
基本理解:mysql
1. 使用場合:sql
觸發器是基於事件的,主要的事件也就是MySQL的增刪改操做,即insert,delete,update。數據庫
2. 觸發器的命名安全
Trigger names exist in the schema namespace, meaning that all triggers must have unique names within a schema. Triggers in different schemas can have the same name.iphone
由於觸發器在單表的命名空間內,因此同一個表的觸發器名稱須要不一樣。不一樣表能夠有相同的觸發器名稱。post
3. 觸發器執行順序性能
若是有相同的update(或者delete,insert)觸發器,就會按照建立的時間來執行。spa
而FOLLOWS 和 PRECEDES 能夠修改trigger的執行順序3d
例如官方的案例:
mysql> CREATE TRIGGER ins_transaction BEFORE INSERT ON account
FOR EACH ROW PRECEDES ins_sum
SET
@deposits = @deposits + IF(NEW.amount>0,NEW.amount,0),
@withdrawals = @withdrawals + IF(NEW.amount<0,-NEW.amount,0);
Query OK, 0 rows affected (0.01 sec)
ins_transaction和ins_sum分別是兩個觸發器的名稱。
4. 觸發器的做用:
1. 安全性。能夠基於數據庫的值使用戶具備操做數據庫的某種權利。
1)能夠基於時間限制用戶的操做,例如不容許下班後和節假日修改數據庫數據。
2)能夠基於數據庫中的數據限制用戶的操做,例如不容許單個商品的購買量大於一個固定值。
2. 審計。能夠跟蹤用戶對數據庫的操做。
1)審計用戶操做數據庫的語句。
2)把用戶對數據庫的更新寫入審計表。
這一塊由於本人沒有用過,就不贅述了,之後有機會來補充
3. 實現複雜的數據完整性規則
實現非標準的數據完整性檢查和約束。觸發器可產生比規則更爲複雜的限制。與規則不一樣,觸發器能夠引用列或數據庫對象。例如,觸發器可回退任何企圖吃進超過本身保證金的期貨。
4. 實現複雜的非標準的數據庫相關完整性規則。
1)觸發器能夠對數據庫中相關的表進行連環更新。這是用得比較多的一種實現功能。
2) 觸發器可以拒絕或回退那些破壞相關完整性的變化,取消試圖進行數據更新的事務。當插入一個與其主健不匹配的外部鍵時,這種觸發器會起做用。
下面的例子我會比較詳細的描述這兩個特性。
5. 同步實時地複製表中的數據。
6. 自動計算數據值,若是數據的值達到了必定的要求,則進行特定的處理。
例如,若是公司的賬號上的資金低於5萬元則當即給財務人員發送警告數據。
(1)插入數據:
當用戶添加一個訂單的時候,咱們須要對商品表格中的庫存(storage)進行相應的改動
mysql> create trigger shop_goods -> after insert on shoppingcar -> for each row -> update goods set storage=storage-new.amount where id=new.g_id -> ; Query OK, 0 rows affected (0.03 sec) mysql>insert into shoppingcar values(1,1,2);
查詢結果:
goods表 +-------+---------+-------------+---------+ | id | gname | description | storage | +-------+---------+---------- --+---------+ | 1 | huawei | rongyao9 | 198 | | 2 | iphone | iphoneX | 100 | +-------+---------+-------------+---------+ shoppingcar表 +----- -+----- -+--------+ | u_id | g_id | amount | +-------+-------+--------+ | 1 | 1 | 2 | +-------+-------+--------+
關於new和old的使用
new表示新的數據行,而old表示舊的數據行
(2)刪除數據
例如,用戶撤銷一個訂單的時候,咱們須要將商品的數量加回去
mysql> create trigger shop_good1 -> after delete on shoppingcar -> for each row -> update goods set storage=storage+old.amount where id=old.g_id; Query OK, 0 rows affected (0.01 sec)
刪除前: mysql> select * from goods; +-----+---------+-------------+---------+ | id | gname | description | storage | +-----+---------+-------------+---------+ | 1 | huawei | rongyao9 | 198 | | 2 | iphone | iphoneX | 100 | +-----+---------+-------------+---------+ 2 rows in set (0.00 sec) mysql> select * from shoppingcar; +------+------+--------+ | u_id | g_id | amount | +------+------+--------+ | 1 | 1 | 2 | +------+------+--------+ 1 rows in set (0.00 sec)
刪除數據: mysql> delete from shoppingcar where g_id=1; Query OK, 1 row affected (0.03 sec)
結果:
(3)更新數據(可增可減)
當用戶對想經過修改購物車的數量來修改本身購買某種商品的數量,那麼,咱們的庫存也須要跟着改動。
mysql> create trigger shop_good2 -> after update on shoppingcar -> for each row -> update goods set storage=storage-new.amount+old.amount where id=new.g_id/old.g_id; Query OK, 0 rows affected (0.14 sec)
查看觸發器命令
show triggers
這個命令只能看到都有哪些的triggers,而看不到trigger的具體信息。
全部觸發器信息都存儲在information_schema數據庫下的triggers表中,可使用SELECT語句查詢。若是有不少個觸發器,最好經過TRIGGER_NAME字段指定查詢某一個觸發器。
例如:
SELECT * FROM information_schema.triggers WHERE TRIGGER_NAME='XXX';
(4)限制條件
條件限制對一些涉及到金額的場合(如開篇提到的)很是重要,在電商的限購數額中也會有應用。
trigger利用delimiter,begin和if語句塊實現限制條件。
例如: mysql> delimiter // mysql> create trigger shop_limit before update on shoppingcar -> for each row -> begin -> if new.amount>3 then -> set new.amount=3; -> elseif new.amount<0 then -> set new.amount=0; -> end if; -> end; // mysql> delimiter ;
條件語句程序塊用begin和end包裹起來實現
delimiter:切換結束符,由於;是MySQL中默認的結束符,若是程序塊中出現;符號,就會引發衝突。最後要將結束符修改回來。注意delimiter與結束符之間有空格,不然會沒法切換。
更新數據前:
更新數據:
mysql> update shoppingcar set amount=4 where u_id=1; Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0
更新數據後:
購買量沒法超過3
關於觸發器與事務
對於事務表(Innodb),before語句後面的判斷語句失敗將會致使回滾事件語句執行的全部更改。觸發器失敗會致使語句失敗,所以觸發器失敗也會致使回滾。對於非事務性表(MyISAM),沒法執行此類回滾,所以儘管語句失敗,但在錯誤點以前執行的任何更改仍然有效。
關於觸發器的使用限制
觸發器執有一些限制:
1. 觸發器不能使用CALL 語句來將數據返回給客戶端或使用動態SQL的存儲過程。但容許存儲過程經過OUT或INOUT 參數將數據返回到觸發器 。
2. 觸發不能使用事務相關的語句,如 START TRANSACTION,COMMIT或ROLLBACK。由於觸發器對update,delete,insert等事件作了處理,而且是按照before,SQL語句,after的順序來執行的,一旦某一步出錯,就會回滾數據。若是在觸發器中使用事務,就會產生矛盾。
參考文章:
https://juejin.im/post/58819729b123db75e08eeae1