MySQL觸發器

觸發器(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     |
+-------+-------+--------+

 

關於newold的使用

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

相關文章
相關標籤/搜索