課程學至金色晨曦科技公司技術總監沙利穆
觸發器
1. 什么是觸發器
觸發器是一種特殊類型的存儲過程,不由用戶直接調用。創建觸發器時會對其進行定義,以便在對特定表或列作特定類型的數據修改時執行。
觸發器從本質上來說,是一個存儲過程,但是它與普通的存儲過程不一樣的地方在於,普通的存儲過程是通過CALL方法進行調用的,而觸發器不是用CALL調用,觸發器是在我們提前設定好的事件出現以后,自動被調用的。
2.為什么要用觸發器
我們在MySQL 5.0中包含對觸發器的支持是由於以下原因:
(1)MySQL早期版本的用戶長期有需要觸發器的要求。
(2)我們曾經許諾支持所有ANSI標准的特性。
(3)您可以使用它來檢查或預防壞的數據進入數據庫。
(4)您可以改變或者取消INSERT, UPDATE以及DELETE語句。
(5)您可以在一個會話中監視數據改變的動作。在這里我假定大家都讀過"MySQL新特性"叢書的第一集--"MySQL存儲過程",那么大家都應該知道MySQL至此存儲過程和函數,那是很重要的知識,因為在觸發器中你可以使用在函數中使用的語句。特別舉個例子:
①復合語句(BEGIN / END)是合法的.
②流控制(Flow-of-control)語句(IF, CASE, WHILE, LOOP, WHILE, REPEAT, LEAVE,ITERATE)也是合法的.
③變量聲明(DECLARE)以及指派(SET)是合法的.
④允許條件聲明.
⑤異常處理聲明也是允許的.
⑥但是在這里要記住函數有受限條件:不能在函數中訪問表.
因此在函數中使用以下語句是非法的。
ALTER 'CACHE INDEX' CALL COMMIT CREATE DELETE
DROP 'FLUSH PRIVILEGES' GRANT INSERT KILL
LOCK OPTIMIZE REPAIR REPLACE REVOKE
ROLLBACK SAVEPOINT 'SELECT FROM table'
'SET system variable' 'SET TRANSACTION'
SHOW 'START TRANSACTION' TRUNCATE UPDATE
在觸發器中也有完全一樣的限制.觸發器相對而言比較新,因此會有(bugs)缺陷.所以我在這里給大家警告,就像我在存儲過程書中所說那樣.不要在含有重要數據的數據庫中使用這個觸發器,如果需要的話在一些以測試為目的的數據庫上使用,同時在你對表創建觸發器時確認這些數據庫是默認的。
2.1 觸發器的主要用途
觸發器主要用於在多個有相互關系的表之間,做一些相互關聯的操作。
2.2 臨時表
更新:更新是用一條新的數據 替換一條舊的數據。在系統中,更新操作分為以下2個步驟:
(1)首先,把舊的數據刪掉
(2)把新的數據插入表中。
在進行以上兩個步驟之前,系統又進行了3個步驟:
(1) 系統創建兩張臨時表,臨時表與要操作的表的結構完全相同,僅是結構相同,但是臨時表中並無數據。
(2) 系統向其中一張臨時表插入要更新的數據,
(3) 系統把要刪除的,即要被更新的數據,插入另外一張臨時表當中。
2.2.1 臨時表的叫法:
NEW:用來插入新數據的臨時表
OLD:數據要被替換的臨時表
2.2.2 臨時表的使用
NEW 列名獲取插入值
2.2.3 使用不同的語句與使用臨時表的關系
使用UPDATA語句:可以使用NEW和OLD兩張臨時表
使用INSERT語句:只能使用NEW臨時表
使用DELETE語句:只能使用OLD臨時表
3.創建觸發器
CREATE TRIGGER 觸發器名稱 觸發時機(BEFORE|AFTER) 事件(INSERT|UPDATE|DELETE)
ON 表名稱 FOR EACH ROW
BEGIN
語句1;
語句2;
語句3;
END
說明:
觸發時機:指在更新、刪除、插入之前BEFORE或之后AFTER
3.1 只有一行代碼的觸發器的例子:
CREATE TRIGGER tr1 AFTER INSERT ON ordertime FOR EACH ROW
insert into ordertime(cid,ordertime) VALUES(NEW.cid,0);
3.2 注意:在同一張表上創建擁有相同觸發時機、事件的觸發器,是不允許的
mysql> CREATE TRIGGER tr2 AFTER INSERT ON ordertime FOR EACH ROW
-> INSERT INTO `order`(oid,cid,pid,onum) VALUES(5,NEW.cid,2,22);
ERROR 1235 (42000): This version of MySQL doesn't yet support 'multiple triggers with the same action time and event for one table'
說明:如果只有一項相同,是可以創建成功的。
在mysql命令行工具中,\c的意義:取消之前的輸入,重新開始輸入。
3.3有多行代碼的觸發器的例子:
DELIMITER //
CREATE TRIGGER t2 BEFORE INSERT ON custom FOR EACH ROW
BEGIN
INSERT INTO `order`(oid,cid,pid,onum) VALUES(5,NEW.cid,1,0);
INSERT INTO `order`(oid,cid,pid,onum) VALUES(6,NEW.cid,2,0);
INSERT INTO `order`(oid,cid,pid,onum) VALUES(7,NEW.cid,3,0);
END
//
3.4 刪除操作的觸發器
CREATE TRIGGER tr3 AFTER DELETE ON custom FOR EACH ROW
DELETE FROM ordertime WHERE cid=OLD.cid;
4.查看觸發器
SHOW TRIGGERS \G
SELECT * FROM information_schema.triggers \G
4.1 SHOW TRIGGERS \G
mysql> SHOW TRIGGERS \G
*************************** 1. row ***************************
Trigger: t2 (觸發器名稱)
Event: INSERT (觸發事件)
Table: custom (觸發事件的表名稱)
Statement: BEGIN
INSERT INTO `order`(oid,cid,pid,onum) VALUES(5,NEW.cid,1,0);
INSERT INTO `order`(oid,cid,pid,onum) VALUES(6,NEW.cid,2,0);
INSERT INTO `order`(oid,cid,pid,onum) VALUES(7,NEW.cid,3,0);
END
Timing: BEFORE (觸發時機)
Created: NULL
sql_mode: NO_ENGINE_SUBSTITUTION
Definer: root@localhost (定義者)
character_set_client: gbk
collation_connection: gbk_chinese_ci
Database Collation: utf8_bin
5. 觸發器的調用
觸發器是在某事件發生后,自動被調用。
5.1 例子1創建觸發器,要求每次錄入一個客戶的信息(custom),就向訂貨次數表(ordertime)中插入一條數據,並設置其訂貨次數(ordertime)為0;
(1)創建觸發器
CREATE TRIGGER t1 AFTER INSERT ON custom FOR EACH ROW
INSERT ordertime(cid,ordertime) VALUES(NEW.cid,0);
(2)驗證觸發器是否實現功能:
mysql> INSERT custom VALUES(110006,'沈陽市糧達飼料有限公司','張海闊');
Query OK, 1 row affected (0.05 sec)
mysql> SELECT * FROM ordertime WHERE cid=110006;
+--------+-----------------+
| cid | ordertime |
+--------+-----------------+
| 110006 | 0 |
+--------+-----------------+
1 row in set (0.00 sec)
5.2 例子2 創建觸發器,要求每次插入訂單信息(order)時,自動把訂貨次數(ordertime)加1。
CREATE TRIGGER t2 AFTER INSERT ON `order` FOR EACH ROW
UPDATE ordertime SET ordertime=(ordertime+1) WHERE cid=NEW.cid;
驗證觸發器功能:
(1) 訂貨次數表 客戶110001 的訂貨次數現在是2
(2)向訂單表插入一條110001的訂單信息記錄
mysql> INSERT `order` VALUES(5,110001,2,22);
Query OK, 1 row affected (0.06 sec)
(3)查看訂貨次數表,客戶110001的訂貨次數自動加1,變成3
mysql> SELECT * FROM ordertime WHERE cid=110001;
+--------+--------------------+
| cid | ordertime |
+--------+--------------------+
| 110001 | 3 |
+--------+--------------------+
1 row in set (0.00 sec)
6.刪除觸發器
DROP TRIGGER 觸發器名稱