【MySQL 12】觸發(fā)器

? ? ?觸發(fā)器是一種特殊類型的存儲過程,它不同于之前的我們介紹的存儲過程。觸發(fā)器主要是通過事件進行觸發(fā)被自動調(diào)用執(zhí)行的。而存儲過程可以通過存儲過程的名稱被調(diào)用。?
??????觸發(fā)器的主要作用就是能夠?qū)崿F(xiàn)比參照完整性更為復(fù)雜的兩張表或多張表之間的數(shù)據(jù)的完整性和一致性,從而保證表中的數(shù)據(jù)的變化符合數(shù)據(jù)庫設(shè)計者確定的業(yè)務(wù)規(guī)則。?
??????觸發(fā)器對表進行插入、更新、刪除的時候會自動執(zhí)行的特殊存儲過程。觸發(fā)器一般用在check約束更加復(fù)雜的約束上面。?
??????觸發(fā)器和普通的存儲過程的區(qū)別是:觸發(fā)器是當(dāng)對某一個表進行操作。諸如:update、insert、delete這些操作的時候,系統(tǒng)會自動調(diào)用執(zhí)行該表上對應(yīng)的觸發(fā)器。?
??????sql server 2005中觸發(fā)器可以分為兩類:dml觸發(fā)器和ddl觸發(fā)器,其中ddl觸發(fā)器它們會影響多種數(shù)據(jù)定義語言語句而激發(fā),這些語句有create、alter、drop語句。

DML觸發(fā)器分為:

1、 after觸發(fā)器(之后觸發(fā))?
??????a、 insert觸發(fā)器?
??????b、 update觸發(fā)器?
??????c、 delete觸發(fā)器?
2、 instead of 觸發(fā)器 (之前觸發(fā))?
3、區(qū)別?
??????after觸發(fā)器:要求只有執(zhí)行某一操作insert、update、delete之后觸發(fā)器才被觸發(fā),且只能定義在表上。?
??????instead of觸發(fā)器:表示并不執(zhí)行其定義的操作(insert、update、delete)而僅是執(zhí)行觸發(fā)器本身。既可以在表上定義instead of觸發(fā)器,也可以在視圖上定義。

inserted 表和 deleted 表

? ?在使用觸發(fā)器時,SQL Server會為每個觸發(fā)器建立兩個特殊的臨時表,即inserted表和deleted表。這兩個表存儲在內(nèi)存中,與創(chuàng)建觸發(fā)器的表具有相同的結(jié)構(gòu),由系統(tǒng)維護和管理,不允許用戶對其進行修改。每個觸發(fā)器只能訪問自己的臨時表,觸發(fā)器執(zhí)行完畢以后,兩表會自動釋放。?
??????(1)inserted表用于存儲insert或update語句所影響的行的副本。當(dāng)執(zhí)行insert或update操作時,新的數(shù)據(jù)行同時被添加到激活觸發(fā)器的基本表和inserted表中。?
??????(2)deleted表用于存儲delete或update語句所影響的行的副本。當(dāng)執(zhí)行delete或update操作時,指定的原數(shù)據(jù)行被從基本表中刪除,然后被轉(zhuǎn)移到deleted表中。一般來說,在基本表和deleted表中不會存在相同的數(shù)據(jù)行。?
?????? 說明:?
??????update操作分為兩步:首先將基本表中修改的原數(shù)據(jù)行轉(zhuǎn)移到deleted表中,然后從inserted表中復(fù)制修改后的新數(shù)據(jù)行到基本表中。也就是說,對于update操作,deleted表中存放的是修改之前的舊值,inserted表中存放的是修改之后的新值。

觸發(fā)器創(chuàng)建語法四要素:

1.監(jiān)視地點(table)?  2.監(jiān)視事件(insert/update/delete)?  3.觸發(fā)時間(after/before)?  4.觸發(fā)事件(insert/update/delete)

語法:

delimiter?&&create?trigger?trigger  Nameafter/before?insert/update/delete?on?表名  for?each?row???#這句話在mysql是固定的  beginsql語句;  end&&

商品表

mysql>?create?table?g(  ????->?id?int?auto_increment?primary?key,????->?name?varchar(10),????->?num?int????->?);

訂單表

mysql>?create?table?o(  ????->?idd?int?auto_increment?primary?key,????->?gid?int,????->?much?int????->?);

插入商品:

mysql>?insert?into?g?(name,num)?value?('juzi',20);mysql>?select?*?from?g;  +----+------+------+|?id?|?name?|?num??|  +----+------+------+|??3?|?juzi?|???20?|  +----+------+------+

如果我們在沒使用觸發(fā)器之前:假設(shè)我們現(xiàn)在賣了3個商品1,我們需要做兩件事

1.往訂單表插入一條記錄

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

2.更新商品表商品1的剩余數(shù)量

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

創(chuàng)建觸發(fā)器:

delimiter?&  mysql>?create?trigger?trg1  ????->?after?insert?on?o????->?for?each?row????->?begin????->?update?g?set?num?=?num?-3?where?id?=?1;????->?end&

執(zhí)行:

insert?into?o(gid,much)?values(1,3)$

結(jié)果:

會發(fā)現(xiàn)商品1的數(shù)量變?yōu)?了,說明在我們插入一條訂單的時候,觸發(fā)器自動幫我們做了更新操作。

但現(xiàn)在會有一個問題,因為我們觸發(fā)器里面num和id都是寫死的,所以不管我們買哪個商品,最終更新的都是商品1的數(shù)量。比如:我們往訂單表再插入一條記錄:insert into o(gid,much) values(2,3),執(zhí)行完后會發(fā)現(xiàn)商品1的數(shù)量變4了,而商品2的數(shù)量沒變,這樣顯然不是我們想要的結(jié)果。我們需要改改我們之前創(chuàng)建的觸發(fā)器。

我們?nèi)绾卧谟|發(fā)器引用行的值,也就是說我們要得到我們新插入的訂單記錄中的gid或much的值。

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

所以現(xiàn)在我們可以這樣來改我們的觸發(fā)器

create?trigger?tg2?  after?insert?on?o?  for?each?row?  begin?  update?g?set?num=num-new.much?where?id=new.gid;(注意此處和第一個觸發(fā)器的不同)?  end$

第二個觸發(fā)器創(chuàng)建完畢,我們先把第一個觸發(fā)器刪掉

drop trigger tg1$

再來測試一下,插入一條訂單記錄:insert into o(gid,much) values(2,3)$

執(zhí)行完發(fā)現(xiàn)商品2的數(shù)量變?yōu)?了,現(xiàn)在就對了。

現(xiàn)在還存在兩種情況:

1.當(dāng)用戶撤銷一個訂單的時候,我們這邊直接刪除一個訂單,我們是不是需要把對應(yīng)的商品數(shù)量再加回去呢?

2.當(dāng)用戶修改一個訂單的數(shù)量時,我們觸發(fā)器修改怎么寫?

我們先分析一下第一種情況:

監(jiān)視地點:o表

監(jiān)視事件:delete

觸發(fā)時間:after

觸發(fā)事件:update

對于delete而言:原本有一行,后來被刪除,想引用被刪除的這一行,用old來表示,old.列名可以引用被刪除的行的值。

那我們的觸發(fā)器就該這樣寫:

create?trigger?tg3  after?delete?on?o  for?each?row  begin  update?g?set?num?=?num?+?old.much?where?id?=?old.gid;(注意這邊的變化)  end$

創(chuàng)建完畢。

再執(zhí)行

delete?from?o?where?oid?=?2$

會發(fā)現(xiàn)商品2的數(shù)量又變?yōu)?0了。

第二種情況:

監(jiān)視地點:o表

監(jiān)視事件:update

觸發(fā)時間:after

觸發(fā)事件:update

對于update而言:被修改的行,修改前的數(shù)據(jù),用old來表示,old.列名引用被修改之前行中的值;

修改的后的數(shù)據(jù),用new來表示,new.列名引用被修改之后行中的值。

那我們的觸發(fā)器就該這樣寫:

create?trigger?tg4  after?update?on?o  for?each?row  begin  update?g?set?num?=?num+old.much-new.much?where?id?=?old/new.gid;  end$

先把舊的數(shù)量恢復(fù)再減去新的數(shù)量就是修改后的數(shù)量了。

我們來測試下:先把商品表和訂單表的數(shù)據(jù)都清掉,易于測試。

假設(shè)我們往商品表插入三個商品,數(shù)量都是10,

買3個商品1:

insert?into?o(gid,much)?values(1,3)$

這時候商品1的數(shù)量變?yōu)?;

我們再修改插入的訂單記錄:

update?o?set?much?=?5?where?oid?=?1$

我們變?yōu)橘I5個商品1,這時候再查詢商品表就會發(fā)現(xiàn)商品1的數(shù)量只剩5了,說明我們的觸發(fā)器發(fā)揮作用了。

以上就是?【MySQL 12】觸發(fā)器的內(nèi)容,更多相關(guān)內(nèi)容請關(guān)注PHP中文網(wǎng)(www.php.cn)!

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點贊13 分享