我們使用MySQL
的過程中可能會有下邊這些需求:
在向t1
表插入或更新資料之前對自動對資料進行校驗,要求m1
列的值必須在1~10
之間,校驗規則如下:
m1
列的值小於1
,則按1
插入。m1
列的值大於10
,則按10
插入。在向t1
表中插入記錄之後自動把這條記錄插入到t2
表。
也就是我們在對錶中的記錄做增、刪、改操作前和後都可能需要讓MySQL
伺服器自動執行一些額外的語句,這個就是所謂的觸發器
的應用場景。
我們看一下定義觸發器
的語句:
CREATE TRIGGER 觸發器名 {BEFORE|AFTER} {INSERT|DELETE|UPDATE} ON 表名 FOR EACH ROW BEGIN 觸發器內容 END
小貼士:
由大括號`{}`包裹並且內部用豎線`|`分隔的語句表示必須在給定的選項中選取一個值,比如`{BEFORE|AFTER}`表示必須在`BEFORE`、`AFTER`這兩個之間選取一個。
其中{BEFORE|AFTER}
表示觸發器內容執行的時機,它們的含義如下:
名稱 | 描述 |
---|---|
BEFORE | 表示在具體的語句執行之前就開始執行觸發器的內容 |
AFTER | 表示在具體的語句執行之後才開始執行觸發器的內容 |
{INSERT|DELETE|UPDATE}
表示具體的語句,MySQL
中目前只支援對INSERT
、DELETE
、UPDATE
這三種型別的語句設定觸發器。
FOR EACH ROW BEGIN ... END
表示對具體語句影響的每一條記錄都執行我們自定義的觸發器內容:
對於INSERT
語句來說,FOR EACH ROW
影響的記錄就是我們準備插入的那些新記錄。
對於DELETE
語句和UPDATE
語句來說,FOR EACH ROW
影響的記錄就是符合WHERE
條件的那些記錄(如果語句中沒有WHERE
條件,那就是代表全部的記錄)。
小貼士: 如果觸發器內容只包含一條語句,那也可以省略BEGN、END這兩個詞兒。
因為MySQL
伺服器會對某條語句影響的所有記錄依次呼叫我們自定義的觸發器內容,所以針對每一條受影響的記錄,我們需要一種存取該記錄中的內容的方式,MySQL
提供了NEW
和OLD
兩個單詞來分別代表新記錄和舊記錄,它們在不同語句中的含義不同:
INSERT
語句設定的觸發器來說,NEW
代表準備插入的記錄,OLD
無效。DELETE
語句設定的觸發器來說,OLD
代表刪除前的記錄,NEW
無效。UPDATE
語句設定的觸發器來說,NEW
代表修改後的記錄,OLD
代表修改前的記錄。現在我們可以正式定義一個觸發器了:
mysql> delimiter $ mysql> CREATE TRIGGER bi_t1 -> BEFORE INSERT ON t1 -> FOR EACH ROW -> BEGIN -> IF NEW.m1 < 1 THEN -> SET NEW.m1 = 1; -> ELSEIF NEW.m1 > 10 THEN -> SET NEW.m1 = 10; -> END IF; -> END $ Query OK, 0 rows affected (0.02 sec) mysql> delimiter ; mysql>
我們對t1
表定義了一個名叫bi_t1
的觸發器
,它的意思就是在對t1
表插入新記錄之前,對準備插入的每一條記錄都會執行BEGIN ... END
之間的語句,NEW.列名
表示當前待插入記錄指定列的值。現在t1
表中一共有4條記錄:
mysql> SELECT * FROM t1; +------+------+ | m1 | n1 | +------+------+ | 1 | a | | 2 | b | | 3 | c | | 4 | d | +------+------+ 4 rows in set (0.00 sec) mysql>
我們現在執行一下插入語句並再次檢視一下t1
表的內容:
mysql> INSERT INTO t1(m1, n1) VALUES(5, 'e'), (100, 'z'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM t1; +------+------+ | m1 | n1 | +------+------+ | 1 | a | | 2 | b | | 3 | c | | 4 | d | | 5 | e | | 10 | z | +------+------+ 6 rows in set (0.00 sec) mysql>
這個INSERT
語句影響的記錄有兩條,分別是(5, 'e')
和(100, 'z')
,這兩條記錄將分別執行我們自定義的觸發器內容。很顯然(5, 'e')
被成功的插入到了t1
表中,而(100, 'z')
插入到表中後卻變成了(10, 'z')
,這個就說明我們的bi_t1
觸發器生效了!
小貼士: 我們上邊定義的觸發器名`bi_t1`的`bi`是`before insert`的首字母縮寫,`t1`是表名。雖然對於觸發器的命名並沒有什麼特殊的要求,但是習慣上還是建議大家把它定義我上邊例子中的形式,也就是`bi_表名`、`bd_表名`、`bu_表名`、`ai_表名`、`ad_表名`、`au_表名`的形式。
上邊只是舉了一個對INSERT
語句設定BEFORE
觸發器的例子,對DELETE
和UPDATE
操作設定BEFORE
或者AFTER
觸發器的過程是類似的,就不贅述了。
檢視當前資料庫中定義的所有觸發器的語句:
SHOW TRIGGERS;
檢視某個具體的觸發器的定義:
SHOW CREATE TRIGGER 觸發器名;
刪除觸發器:
DROP TRIGGER 觸發器名;
這幾個命令太簡單了,就不舉例子了啊~
觸發器內容中不能有輸出結果集的語句。
比方說:
mysql> delimiter $ mysql> CREATE TRIGGER ai_t1 -> AFTER INSERT ON t1 -> FOR EACH ROW -> BEGIN -> SELECT NEW.m1, NEW.n1; -> END $ ERROR 1415 (0A000): Not allowed to return a result set from a trigger mysql>
顯示的ERROR
的意思就是不允許在觸發器內容中返回結果集!
觸發器內容中NEW代表記錄的列的值可以被更改,OLD代表記錄的列的值無法更改。
NEW
代表新插入或著即將修改後的記錄,修改它的列的值將影響INSERT和UPDATE語句執行後的結果,而OLD
代表修改或刪除之前的值,我們無法修改它。比方說如果我們非要這麼寫那就會報錯的:
mysql> delimiter $ mysql> CREATE TRIGGER bu_t1 -> BEFORE UPDATE ON t1 -> FOR EACH ROW -> BEGIN -> SET OLD.m1 = 1; -> END $ ERROR 1362 (HY000): Updating of OLD row is not allowed in trigger mysql>
可以看到提示的錯誤中顯示在觸發器中OLD
代表的記錄是不可被更改的。
在BEFORE觸發器中,我們可以使用SET NEW.列名 = 某個值
的形式來更改待插入記錄或者待更新記錄的某個列的值,但是這種操作不能在AFTER觸發器中使用,因為在執行AFTER觸發器的內容時記錄已經被插入完成或者更新完成了。
比方說如果我們非要這麼寫那就會報錯的:
mysql> delimiter $ mysql> CREATE TRIGGER ai_t1 -> AFTER INSERT ON t1 -> FOR EACH ROW -> BEGIN -> SET NEW.m1 = 1; -> END $ ERROR 1362 (HY000): Updating of NEW row is not allowed in after trigger mysql>
可以看到提示的錯誤中顯示在AFTER觸發器中是不允許更改NEW
代表的記錄的。
如果我們的BEFORE
觸發器內容執行過程中遇到了錯誤,那這個觸發器對應的具體語句將無法執行;如果具體的操作語句執行過程中遇到了錯誤,那與它對應的AFTER
觸發器的內容將無法執行。
小貼士: 對於支援事務的表,不論是執行觸發器內容還是具體操作語句過程中出現了錯誤,會把這個過程中所有的語句都回滾。當然,作為小白的我們並不知道啥是個事務,啥是個回滾,這些進階內容都在《MySQL是怎樣執行的:從根兒上理解MySQL》中呢~
有時候我們想讓MySQL
伺服器在某個時間點或者每隔一段時間自動地執行一些語句,這時候就需要去建立一個事件
。
建立事件的語法如下:
CREATE EVENT 事件名 ON SCHEDULE { AT 某個確定的時間點| EVERY 期望的時間間隔 [STARTS datetime][END datetime] } DO BEGIN 具體的語句 END
事件
支援兩種型別的自動執行方式:
在某個確定的時間點執行。
比方說:
CREATE EVENT insert_t1_event ON SCHEDULE AT '2019-09-04 15:48:54' DO BEGIN INSERT INTO t1(m1, n1) VALUES(6, 'f'); END
我們在這個事件
中指定了執行時間是'2019-09-04 15:48:54'
,除了直接填某個時間常數,我們也可以填寫一些表示式:
CREATE EVENT insert_t1 ON SCHEDULE AT DATE_ADD(NOW(), INTERVAL 2 DAY) DO BEGIN INSERT INTO t1(m1, n1) VALUES(6, 'f'); END
其中的DATE_ADD(NOW(), INTERVAL 2 DAY)
表示該事件將在當前時間的兩天後執行。
每隔一段時間執行一次。
比方說:
CREATE EVENT insert_t1 ON SCHEDULE EVERY 1 HOUR DO BEGIN INSERT INTO t1(m1, n1) VALUES(6, 'f'); END
其中的EVERY 1 HOUR
表示該事件將每隔1個小時執行一次。預設情況下,採用這種每隔一段時間執行一次的方式將從建立事件的事件開始,無限制的執行下去。我們也可以指定該事件開始執行時間和截止時間:
CREATE EVENT insert_t1 ON SCHEDULE EVERY 1 HOUR STARTS '2019-09-04 15:48:54' ENDS '2019-09-16 15:48:54' DO BEGIN INSERT INTO t1(m1, n1) VALUES(6, 'f'); END
如上所示,該事件將從'2019-09-04 15:48:54'開始直到'2019-09-16 15:48:54'為止,中間每隔1個小時執行一次。
小貼士: 表示事件間隔的單位除了HOUR,還可以用YEAR、QUARTER、MONTH、DAY、HOUR、 MINUTE、WEEK、SECOND、YEAR_MONTH、DAY_HOUR、DAY_MINUTE、DAY_SECOND、HOUR_MINUTE、HOUR_SECOND、MINUTE_SECOND這些單位,根據具體需求選用我們需要的時間間隔單位。
在建立好事件
之後我們就不用管了,到了指定時間,MySQL
伺服器會幫我們自動執行的。
檢視當前資料庫中定義的所有事件的語句:
SHOW EVENTS;
檢視某個具體的事件的定義:
SHOW CREATE EVENT 事件名;
刪除事件:
DROP EVENT 事件名;
這幾個命令太簡單了,就不舉例子了啊~
預設情況下,MySQL
伺服器並不會幫助我們執行事件,除非我們使用下邊的語句手動開啟該功能:
mysql> SET GLOBAL event_scheduler = ON; Query OK, 0 rows affected (0.00 sec) mysql>
小貼士: event_scheduler其實是一個系統變數,它的值也可以在MySQL伺服器啟動的時候通過啟動引數或者通過組態檔來設定event_scheduler的值。這些所謂的系統變數、啟動引數、組態檔的各種東東並不是我們小白現在需要掌握的,大家忽略它們就好了~
推薦學習:
以上就是一起聊聊MySQL基礎之觸發器和事件的詳細內容,更多請關注TW511.COM其它相關文章!