首先,我們來了解一下什麼是觸發器,觸發器,就是在對一張表資料進行增(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 ordforeach row #固定寫法,為的是批量操作
begin
update goodset 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 ordforeach row
begin
update goodset 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 ordforeach row
begin
update goodset 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 ordforeach row
begin
declare has_numint;select good_num into has_num from good where good_id = new.good_id;if has_num < new.ord_num thenset new.ord_num =has_num;
endif;
update goodset good_num =0 where good_id = new.good_id;
end$
我這個地方調了很久,一直是下完訂單之後超過庫存數量後,good表更新的值有問題,不是為0。
原來是這個觸發器是before發生,與之前的after觸發器衝突了。兩個觸發器都起了作用,更新了兩遍good表。
mysql建立觸發器
注 觸發器中不能呼叫儲存過程,觸發器功能應盡量簡單 use d database name 切換到資料庫 set names utf8 drop if exists when update can use drop trigger if exists tr update bind sno delim...
mysql建立觸發器
很多時候為了提高查詢效率,我們會在一些表當中增加冗餘字段,例如在客戶表裡面儲存用油卡號,但是如果客戶掛失原卡,申請了新的油卡,冗餘欄位就不正確了,這時候應該怎麼辦呢?我們可以建立乙個觸發器,當客戶插入新的油卡資料的時候同時更新客戶資料。delimiter create trigger update ...
mysql 建立觸發器
參考 建立觸發器的語法如下 create trigger trigger name trigger time trigger event on tbl name for each row trigger stmt trigger time 是觸發器的觸發時間,可以是before 或者after,be...