mysql創建觸發器


首先,我們來了解一下什么是觸發器,觸發器,就是在對一張表數據進行增(insert),刪(delete),改(update)的時候,為了保持數據的一致性,對別的表也要進行相應的數據修改。

我們都知道mysql最后事務提交后,數據是會保存到磁盤上的,那么每次在insert,delete,update時候舊數據和新數據,會在內存中生成臨時的行數據,分別叫old和new。例如要inset插入一條數據的時候,會先將這行數據放在內存中,叫new臨時表。update的時候,會先將更新之前的數據放在內存old表中,即將更新的數據放在內存new表中。然后通過內存,把數據持久化保存到磁盤中,觸發器的before和after就是相對於數據是從內存持久化到數據庫之前還是之后觸發相對而言的。

舉個例子吧:

假設有商品goods表:商品id,商品名字,商品數量

good_id  good_name  num

    1            books         10

    2            phones       20

    3            snacks        30

有訂單ord表:訂單id,商品id,訂單數量。

假設購買了10部手機,訂單表中插入10部手機,那么商品中對應手機的數量是不是要減少10部。這完全可以通過編寫高級程序代碼來實現,但是高級程序要多次與數據庫交互,浪費時間。

這也可以通過觸發器來實現,就減少了程序與數據庫的交互,節省時間。

翻譯一下上面的業務,就是在ord表中插入一條訂單時,要在商品表中,對應的商品的對應num數量要減少,怎么寫這個觸發器呢?

 

 

1.創建插入數據時候的觸發器

 

先修改mysql默認的結束符號位$

delimiter $  //結尾不要帶分號

 

代碼如下:

create trigger t1
after #是在ord表上創建觸發器t1,當ord表插入數據之后觸發
insert        #在創建觸發器t1,在內存數據持久化到磁盤,insert ord 表之后操作
on ord
for each row #固定寫法,為的是批量操作 begin update good set good_num = good_num - new.ord_num where good_id=new.good_id; end$

當我向訂單表插入數據時,商品表數據自動更新了。這就是觸發器的作用。其中for each row是固定代碼,就是如果做批量更新,每行都是這樣操作。

其中new.ord_num 和new.good_id 是表示在內存中的臨時表,即將要插入的ord表中的那一行數據。本質是就是

ord_id  good_id   ord_num

   1           2          10

 這行數據,只不過是暫時在內存new表中中存放。

 

2.創建刪除時候的觸發器

如何這時候訂單1,撤銷了,刪除了,那么對應的2號商品Phone是不是要增加10,回到20。

這就是刪除觸發器,

 

 代碼如下:

create trigger t2
after #是在ord表上創建觸發器t1,當ord表插入數據之后觸發
delete
on ord
for each row
begin
    update good set good_num = good_num + old.ord_num where good_id=old.good_id;
end$

 

3.創建更新時候的觸發器

數據庫的更新,其實是分兩步走,第一步是先將舊數據刪除,保存在old臨時表,再將新數據插入,保存在new臨時表中。

那么我更新訂單的數量,本來是買10部手機,那我想買12部手機了,這時候商品good表應該再減2部手機,這兩部是new.12 - old.10,新表保存了12,舊表保存了10

 

 

 

代碼如下:

create trigger t3
after #是在ord表上創建觸發器t1,當ord表插入數據之后觸發
update
on ord
for each row
begin
    update good set good_num = good_num - (new.ord_num-old.ord_num) where good_id=old.good_id;
end$

這里where good_id = old.good_id 也可以寫成 good_id = new.good_id 應為這兩張表中保存的都是這種這個商品的id。

 

到此為止,我就把這三個操作的觸發器都創建了一遍。

現在還沒有說 在創建觸發器時,before和after有什么區別?

其實要理解這個區別,一定要牢記的就是,mysql在插入操作的時候,是先將數據保存在內存new表中,再將數據寫入磁盤,刪除操作時,是先將要刪除的數據保存在內存的old表中,再寫入磁盤完成刪除。

這個before和after是相對這個臨時表 new或old相對而言的。定義after就是指在臨時表從內存更新到磁盤之后才觸發,定義before就是指,在臨時表更新到磁盤之前觸發。

如下面的業務場景,如果我用戶購買商品,想購買25部手機,但是庫存中只有10部手機,我想通過數據庫來判斷如果想購買的手機超過了庫存量,就只讓用戶購買庫存量這么多手機,不能超額購買。

針對這個問題怎么實現呢?

是不是當用戶購買25部手機時,先去查詢good表,手機還剩多少部手機,如果庫存手機數大於 25部,就讓購買。如果不夠時,將要購買的手機數量個更新為當前的庫存最大數量。

 

 

 

 初始phone是有20部,但是要買25部,只能讓購買20部,代碼如下:

create trigger t4
before
insert
on ord
for each row
begin
    declare has_num int;
    select good_num into has_num from good where good_id = new.good_id;
    
    if has_num < new.ord_num then

    set new.ord_num = has_num;

    end if;

    update good set good_num =0 where good_id = new.good_id;   

end$

我這個地方調了很久,一直是下完訂單之后超過庫存數量后,good表更新的值有問題,不是為0。

原來是這個觸發器是before發生,與之前的after觸發器沖突了。兩個觸發器都起了作用,更新了兩遍good表。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM