【MySql】9.觸發器

   觸發器是MySQL響應如下任意語句而自動執行的一條MySQL語句(或位於BEGINEND語句之間的一組語句):mysql

DELETEsql

INSERTapp

UPDATEide

    使用觸發器,須要MySQL5或以後的版本支持。測試

1、觸發器基本操做

1、建立觸發器

建立觸發器時,須要給出4條信息:spa

  惟一的觸發器名;(雖然MySQL5容許不一樣的表上的觸發器名稱相同,但通常最好不要這麼作。)blog

  觸發器關聯的表;事件

  觸發器響應的事件;rem

  觸發器什麼時候執行;get

  語法結構:

create trigger trigger_name (BEFORE|AFTER) (delete|update|insert) on table_name

for each row  -- 這句話在mysql是固定的,通知觸發器每隔一行執行一次動做,而不是對整個表

BEGIN

要觸發的sql語句;

END;


CREATE TABLE t_goods(id int,goods_name varchar(20),quantity int,add_date date);


delimiter |

create triggert_trig before insert on t_goods for each row

BEGIN

set NEW.add_date=CURRENT_DATE();

END

|

delimiter ;


insert into t_goods(id,goods_name,quantity) values(1,'apple',50);


select * fromt_goods;

wKiom1NwhZbwCQyQAABBI8GcS0g743.jpg


2、刪除觸發器

DROP TRIGGER [schema_name.]trigger_name

drop trigger t_trig;


3、查看觸發器

SHOW TRIGGERS [ FROM DBNAME [ like '' ] ];

show triggers;

wKioL1NwheHyK6DIAAGRE9u4GeM635.jpg

2、一個具體的實例


1.首先咱們來建立兩張表


-- 商品表

create table g

(

id int primary key auto_increment,

name varchar(20),

num int

);


-- 訂單表

create table o

(

oid int primary key auto_increment,

gid int,

much int

);


2.向商品表插入數據

insert into g(name,num) values('商品1',10),('商品2',10),('商品3',10);

wKioL1NwiFHT0FJvAAA0f69vTRo213.jpg

若是咱們在沒使用觸發器以前:假設咱們如今賣了3個商品1,咱們須要作兩件事

(1)往訂單表插入一條記錄

insert into o(gid,much) values(1,3);

wKiom1NwiT-z5pwyAAAZx4xSXjw917.jpg

(2)更新商品表商品1的剩餘數量

update g set num=num-3 where id=1;

wKioL1NwiVyC6JmXAAAyqLi6PKQ505.jpg


如今來建立一個觸發器:當生成一個訂單(賣出商品了),即向訂單表o中插入一條記錄時,更新商品表g中相應商品的剩餘數量

create trigger tg1

after insert on o

for each row

begin

update g set num=num-3 where id=1;

end

-- 商品1賣出了3件

insert into o(gid,much) values(1,3);  -- 會發現商品1的數量變爲7了

說明在咱們插入一條訂單的時候,觸發器自動幫咱們作了更新操做。


   但如今會有一個問題,由於咱們觸發器裏面num和id都是寫死的,因此無論咱們買哪一個商品,最終更新的都是商品1的數量。好比:咱們往訂單表再插入一條記錄:

insert into o(gid,much) values(2,3),執行完後會發現商品1的數量變4了,而商品2的數量沒變,這樣顯然不是咱們想要的結果。咱們須要改改咱們以前建立的觸發器。

咱們如何在觸發器引用行的值,也就是說咱們要獲得咱們新插入的訂單記錄中的gid或much的值。

對於insert而言,新插入的行用new來表示,行中的每一列的值用new.列名來表示。

如今來更改上面的觸發器

drop trigger tg1;  -- 同一個表上不能建立多個觸發時間和觸發事件都相同並做用於同一張表的觸發器,因此先刪除tg1

create trigger tg2

after insert on o

for each row

begin

update g set num=num-new.much where id=new.gid;

end

-- 再來測試。。

insert into o(gid,much) values(2,3);  -- 發現商品2的數量變爲7了

wKiom1Nwi2PwmV_0AAA3XrfbqMU379.jpg

考慮另外一種狀況:當用戶撤銷一個訂單的時候,咱們這邊直接刪除一個訂單,這時就須要把對應的商品數量再加回去

分析:

監視地點:o表

監視事件:delete

觸發時間:after

觸發事件:update

對於delete而言:本來有一行,後來被刪除,想引用被刪除的這一行,用old來表示,old.列名能夠引用被刪除的行的值。

create trigger tg3

after delete on o

for each row

begin

update g set num = num + old.much where id = old.gid;

end


-- 測試。。

delete from o where oid = 2;  -- 發現商品2的數量又變爲10了


再考慮:當用戶修改一個訂單的數量時,咱們觸發器修改怎麼寫?

分析:

監視地點:o表

監視事件:update

觸發時間:after

觸發事件:update

對於update而言:被修改的行,修改前的數據,用old來表示,old.列名引用被修改以前行中的值;

修改的後的數據,用new來表示,new.列名引用被修改以後行中的值

create trigger tg4

after update on o

for each row

begin

update g set num = num+old.much-new.much where id = old.gid;(或:where id = new.gid)

end

測試:

update o set much = 5 where oid = 1

咱們變爲買5個商品1,這時候再查詢商品表就會發現商品1的數量只剩5了,說明咱們的觸發器發揮做用了。


3、before和after的區別


假設:假設商品表有商品1,數量是10;

咱們往訂單表插入一條記錄:

insert into o(gid,much) values(1,20);

會發現商品1的數量變爲-10了。這就是問題的所在,由於咱們以前建立的觸發器是after,也就是說觸發的語句是在插入訂單記錄以後才執行的,這樣咱們就沒法判斷新插入訂單的購買數量。


先講一下after和before的區別:

after是先完成數據的增刪改,再觸發,觸發的語句晚於監視的增刪改操做,沒法影響前面的增刪改動做;也就是說先插入訂單記錄,再更新商品的數量;

before是先完成觸發,再增刪改,觸發的語句先於監視的增刪改,咱們就有機會判斷,修改即將發生的操做;

咱們用一個典型案例來區分它們的區別,新建一個觸發器:

監視地點: 商品表o

監視事件:insert

觸發時間:before

觸發事件:update

案例:當新增一條訂單記錄時,判斷訂單的商品數量,若是數量大於10,就默認改成10


create trigger tg6

before insert on o

for each row

begin

  if new.much > 10 then

    set new.much = 10;

  end if;

  update g set num = num - new.much where id = new.gid;

end


執行完,把以前建立的after觸發器刪掉,再來插入一條訂單記錄:

insert into o(gid,much) valus(1,20)

執行完會發現訂單記錄的數量變爲10,商品1的數量變爲0了,就不會出現負數了。

另外一個區別:

before:(insert、update)能夠對new進行修改。

after不能對new進行修改。

二者都不能修改old數據;對於DELETE語句,只有old才合法。

舉例說明:

mysql> select * from t1;
+------+------+
| id   | name |
+------+------+
|   1 |   aa  |
+------+------+

mysql> select * from t2;
Empty set (0.00 sec)

before觸發器代碼:

CREATE TRIGGER t1_before BEFORE update ON t1
FOR EACH ROW
BEGIN
 set new.id=new.id+11;
 set new.name=upper(new.name);  -- 轉換爲大寫字母
 insert into t2 values(new.id,new.name);
END


mysql> update t1 set name='bbs' where id=1;

mysql> select * from t1;
+------+------+
| id   | name |
+------+------+
|   12 | BBS  |
+------+------+

mysql> select * from t2;
+------+------+
| id   | name |
+------+------+
|   12 | BBS  |
+------+------+

NEW值,已經被修改。

after觸發器代碼:

CREATE TRIGGER t1_after AFTER update ON t1
FOR EACH ROW
BEGIN
 set new.id=new.id+11;
 set new.name=upper(new.name);
 insert into t2 values(new.id,new.name);
END

運行時會報錯:

[Err] 1362 - Updating of NEW row is not allowed in after trigger

因爲是after觸發器,不能對NEW值修改,因此報錯。

因此修改after觸發器:

drop trigger if exists t1_after;
CREATE TRIGGER t1_after AFTER update ON t1
FOR EACH ROW
BEGIN
 insert into t2 values(old.id,old.name);

-- 或insert into t2 values(new.id,new.name);都能運行
END

mysql> select * from t1;
+------+------+
| id   | name |
+------+------+
|   1 |   aa  |
+------+------+

mysql> select * from t2;
Empty set (0.00 sec)

mysql> update t1 set name='bbs' where id=1;

mysql> select * from t1;
+------+------+
| id   | name |
+------+------+
|    1 | bbs  |
+------+------+

mysql> select * from t2;+------+------+| id   | name |+------+------+|    1 | aa   |+------+------+

相關文章
相關標籤/搜索