觸發器(trigger)是數據庫中的一個很重要的、很實用的基于事件的處理器,在處理一些業務需求的時候,使用觸發器會很方便。似乎在《高性能MySQL》中,對觸發器作了一定的描述,也提到使用中的一些優勢和局限性,但感覺還是不能完全理解觸發器的全部功能和實現。于是自己在網上看了一些文章,結合官網(https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html)中的案例,寫下這篇總結。
?
基本理解:
1. 使用場合:
觸發器是基于事件的,主要的事件也就是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.
因為觸發器在單表的命名空間內,所以同一個表的觸發器名稱需要不同。不同表可以有相同的觸發器名稱。
3. 觸發器執行順序
如果有相同的update(或者delete,insert)觸發器,就會按照創建的時間來執行。
而FOLLOWS 和 PRECEDES 可以修改trigger的執行順序
例如官方的案例:
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)進行相應的改動
?
查詢結果:
?
關于new和old的使用
new表示新的數據行,而old表示舊的數據行
?
(2)刪除數據
例如,用戶撤銷一個訂單的時候,我們需要將商品的數量加回去
?
?
?
結果:
?
?
(3)更新數據(可增可減)
當用戶對想通過修改購物車的數量來修改自己購買某種商品的數量,那么,我們的庫存也需要跟著改動。
?
查看觸發器命令
show triggers
這個命令只能看到都有哪些的triggers,而看不到trigger的具體信息。
?
所有觸發器信息都存儲在information_schema數據庫下的triggers表中,可以使用SELECT語句查詢。如果有很多個觸發器,最好通過TRIGGER_NAME字段指定查詢某一個觸發器。
例如:
SELECT * FROM information_schema.triggers WHERE TRIGGER_NAME='XXX';
?
?
(4)限制條件
條件限制對一些涉及到金額的場合(如開篇提到的)非常重要,在電商的限購數額中也會有應用。
trigger利用delimiter,begin和if語句塊實現限制條件。
條件語句程序塊用begin和end包裹起來實現
delimiter:切換結束符,因為;是MySQL中默認的結束符,如果程序塊中出現;符號,就會引起沖突。最后要將結束符修改回來。注意delimiter與結束符之間有空格,否則會無法切換。
?
更新數據前:
?
更新數據:
?
更新數據后:
購買量無法超過3
?
?
關于觸發器與事務
對于事務表(Innodb),before語句后面的判斷語句失敗將會導致回滾事件語句執行的所有更改。觸發器失敗會導致語句失敗,因此觸發器失敗也會導致回滾。對于非事務性表(MyISAM),無法執行此類回滾,因此盡管語句失敗,但在錯誤點之前執行的任何更改仍然有效。
?
關于觸發器的使用限制
觸發器執有一些限制:
1. 觸發器不能使用CALL 語句來將數據返回給客戶端或使用動態SQL的存儲過程。但允許存儲過程通過OUT或INOUT 參數將數據返回到觸發器 。
2. 觸發不能使用事務相關的語句,如 START TRANSACTION,COMMIT或ROLLBACK。因為觸發器對update,delete,insert等事件做了處理,并且是按照before,SQL語句,after的順序來執行的,一旦某一步出錯,就會回滾數據。如果在觸發器中使用事務,就會產生矛盾。