MySQL從刪庫到跑路_高階(五)——觸發器
作者:天山老妖S
連結:http://blog.51cto.com/9291927
一、觸發器簡介
1、觸發器簡介
觸發器是和表關聯的特殊的儲存過程,可以再插入,刪除或修改表中的資料時觸發執行,比資料庫本身標準的功能有更精細和更復雜的資料控制能力。
2、觸發器的優點
A、安全性
可以基於資料庫的值使使用者具有操作資料庫的某種權利。可以基於時間限制使用者的操作,例如不予許下班後和節假日修改資料庫資料;可以基於資料庫中的資料限制使用者的操作,例如不允許股票的價格的升幅一次超過10%。
B、審計
可以跟蹤使用者對資料庫的操作。審計使用者操作資料庫的語句;把使用者對資料庫的更新寫入審計表。
C、實現複雜的資料完整性規則
實現非標準的資料完整性檢查和約束。觸發器可產生比規則更為複雜的限制。與規則不同,觸發器可以引用列或資料庫物件。例如,觸發器可回退任何企圖吃進超過自己保證金的期貨。提供可變的預設值。
D、實現複雜的非標準的資料庫相關完整性規則。
觸發器可以對資料庫中相關的表進行連環更新。
在修改或刪除時級聯修改或刪除其它表中的與之匹配的行。
在修改或刪除時把其它表中的與之匹配的行設成NULL值。
在修改或刪除時把其它表中的與之匹配的行級聯設成預設值。
觸發器能夠拒絕或回退那些破壞相關完整性的變化,取消試圖進行資料更新的事務。
E、同步實時地複製表中的資料。
F、SQL觸發器提供了執行計劃任務的另一種方法。自動計算資料值,如果資料的值達到一定的要求,則進行特定的處理。例如,如果公司的賬號上的資金低於5萬元則立即給財務人員傳送警告資料。
3、觸發器的限制
A、觸發程式不能呼叫將資料返回客戶端的儲存程式,也不能使用採用CALL語句的動態SQL語句,但是允許儲存程式通過引數將資料返回觸發程式,也就是儲存過程或者函式通過OUT或者INOUT型別的引數將資料返回觸發器是可以的,但是不能呼叫直接返回資料的過程。
B、不能在觸發器中使用以顯示或隱式方式開始或結束事務的語句,如 SELECT TRANS-ACTION,COMMIT或ROLLBACK。
二、觸發器的使用
1、建立觸發器
建立觸發器的語法:
CREATE TRIGGER trigger_name trigger_time trigger_event ON tb_name FOR EACH ROW trigger_stmt
trigger_name:觸發器的名稱。
trigger_time:觸發時機,為BEFIRE或者AFTER。
trigger_event:觸發事件,為INSERT、DELETE或者UPDATE。
tb_name:表示建立觸發器的表名,在哪張表上建立觸發器。
trigger_stmt:觸發器的程式體,可以是一條SQL語句或者是用BEGIN和END包含的多條語句。
FOR EACH ROW 表示任何一條記錄上的操作滿足觸發事件都會觸發該觸發器。
MySQL除了對INSERT、UPDATE、DELETE基本操作進行定義外,還定義了LOAD DATA和REPLACE語句,這兩種語句也能引起上述6種類型的觸發器的觸發。
LOAD DATA 語句用於將一個檔案裝入到一個數據表中,想當於一系列的INSERT操作。
REPLACE語句一般來說和INSERT語句很像,只是在表中有primary key 或 unique 索引一致時,會先刪除原來的資料,然後增加一條新資料。
INSERT型觸發器:插入某一行時啟用觸發器,通過INSERT、LOAD DATA、REPLACE語句觸發;
UPDATE型觸發器:更改某一行時啟用觸發器,通過UPDATE語句觸發;
DELETE型觸發器:刪除某一行時啟用觸發器,通過DELETE、REPLACE語句觸發。
變數宣告:
DECLARE var_name[,...] type [DEFAULT value]
對變數賦值採用SET語句,語法為:
SET var_name = expr [,var_name = expr] ...
MySQL中定義了NEW和OLD,用來表示觸發器的所在表中,觸發了觸發器的哪一行資料。
在INSERT型觸發器中,NEW用來表示將要(BEFORE)或已經(AFTER)插入的新資料;
在UPDATE型觸發器中,OLD用來表示將要或已經被修改的原資料,NEW用來表示將要或已經修改為的新資料;
在DELETE型觸發器中,OLD用來表示將要或已經被刪除的原資料;
使用方法:NEW.columnName(columnName為相應資料表某一列名)
另外,OLD是隻讀的,而NEW則可以在觸發器中使用SET賦值,不會再次觸發觸發器,造成迴圈呼叫。
2、刪除觸發器
DROP TRIGGER [IF EXISTS] [schema_name.] trigger_name
schema_name是資料庫的名稱,是可選的。如果省略了schema,將從當前資料庫中捨棄觸發程式。trigger_name是要刪除的觸發器的名稱。
3、觸發器資訊檢視
在MySQL中,所有的觸發器的定義都存在於INFORMATION_SCHEMA資料庫的triggers表中,可以通過查詢命令SELECT來檢視,具體語法如下:
SHOW TRIGGERS [FROM schema_name];
觸發器的執行順序
InnoDB資料庫,若SQL語句或觸發器執行失敗,MySQL會回滾事務,有:
A、如果BEFORE觸發器執行失敗,SQL無法正確執行。
B、SQL執行失敗時,AFTER型觸發器不會觸發。
C、AFTER型別的觸發器執行失敗,SQL會回滾。
MySQL的觸發器是按照BEFORE觸發器、行操作、AFTER觸發器的順序執行的,其中任何一步發生錯誤都不會繼續執行剩下的操作,如果對事務表進行的操作,如果出現錯誤,那麼將會被回滾,資料可能會出錯。
三、觸發器應用
1、實現業務邏輯
客戶下訂單訂購商品,商品表自動減少數量。
在商品表建立刪除觸發器,刪除某商品,自動刪除該商品的訂單。建立產品表,有產品編號,產品名稱、產品數量和產品價格四列,其中產品編號自增長列,並且設定成主鍵。
create table product
(
pid int PRIMARY KEY AUTO_INCREMENT,
pname VARCHAR(10),
price DOUBLE,
pnum INT)ENGINE=innoDB default CHARSET=utf8;
建立訂單表,有三列,訂單編號、產品編號和數量,其中訂單編號自增長列,並設定成主鍵。
create table orders
(oid INT PRIMARY KEY AUTO_INCREMENT,
pid INT,
onum INT)ENGINE=innoDB DEFAULT CHARSET=utf8;
插入三種產品,產品名稱和數量以及價格。
insert into product(pname,pnum,price) values('桃子',100,2);
insert into product(pname,pnum,price) values('蘋果',80,8);
insert into product(pname,pnum,price) values('香蕉',50,5);
在訂單表上建立觸發器,當有訂單,會根據訂單的產品編號和數量自動減少產品的數量。觸發器中NEW代表一個表,存放插入的訂單記錄。
create trigger trigger_order AFTER INSERT ON orders FOR EACH ROW BEGIN UPDATE product SET pnum = pname-NEW.onum where pid = NEW.pid; END
插入兩個訂單
INSERT INTO orders(pid,onum) VALUES(1,10); INSERT INTO orders(pid,onum) VALUES(2,5);
檢視產品表,可以看到對應的產品數量減少。操作由訂單表的Insert觸發器完成。
在訂單表上建立新的觸發器,當訂單定的某產品產品數量大於產品庫存,禁止下訂單,也就是禁止在訂單表中插入記錄。
一張表中只能有一個INSERT型別的觸發器,先刪除INSERT觸發器。
drop trigger trigger_order;
MySQL不能在觸發器中通過回滾事務取消操作,但如果觸發器的SQL語句執行過程中出現錯誤,會自動撤銷操作,曲線實現事務回滾。
create trigger trigger_order
BEFORE INSERT ON orders FOR EACH ROW
BEGINDECLARE var int;DECLARE mesg varchar(20);
SELECT pnum INTO var FROM product where pid=NEW.pid;IF var<NEW.onum
THEN SELECT XXXX INTO mesg;ELSE
UPDATE product SET pnum=pnum-NEW.onum where pid=NEW.pid;
END IF;
END
插入訂單,看看如果庫存不夠是否還能插入成功。
INSERT INTO orders(pid, onum) VALUES(1,110);
2、實現安全
A、限制插入記錄的日期
在訂單表上建立插入觸發器,週六週日不允許下訂單。
create trigger trigger_limitDateBEFORE INSERT ON orders FOR EACH ROWBEGINDECLARE mesg varchar(10);
IF DAYNAME(now())='sunday' or DAYNAME(now())='saturday'
THEN SELECT XXXXX INTO mesg;
ELSE
SET mesg='允許插入訂單';END IF;END
驗證上面建立的觸發器是否工作正常,看看當前時間是否是週六週日,向訂單表插入記錄,檢查是否能夠成功。
insert into orders(pid,onum) values(3,30)
B、限制資料更改的範圍
在產品表上建立更新觸發器,限制產品價格一次上調不能超過20%。
觸發器設定成before update,在更改前檢查價格增長幅度是否超過20%,如果超過就產生錯誤,取消操作。
更新操作分為兩步,第一步是刪除原來的記錄,第二部是插入新記錄。原來的記錄在old表中,新記錄在new表中。觸發器中new.price存放的是新價格,old.price是原來的價格。
create trigger trigger_limitIncreasePrice
BEFORE UPDATE ON product FOR EACH ROW
BEGIN
DECLARE mesg varchar(10);if (NEW.price-OLD.price)*100/OLD.price > 20
then select XXXX into mesg;else
set mesg='更改成功';
end if;
END
驗證觸發器
update product set price = 20 where pid = 1;
3、實現資料完整性
使用觸發器可以限制表插入某列的數值範圍。
建立一個學生表,有四列,姓名、性別、手機和郵箱。
create table personinfo
(
sname VARCHAR(5),
sex CHAR(1),
phone VARCHAR(11)
)ENGINE=innoDB default CHARSET=utf8;
A、指定性別列的取值範圍
建立觸發器,限制性別列,只允許輸入“男”和“女”。
before insert觸發器,不滿足條件執行有錯誤SQL語句,退出。
create trigger trigger_limitSexbefore insert on personinfo for each rowbegindeclare mesg varchar(10);
if NEW.sex='男' or NEW.sex='女'
then set mesg='更改成功';
else
select xxxx into mesg;end if;End
驗證觸發器
insert into personinfo VALUES('孫悟空','女','18900000000'); insert into personinfo VALUES('唐僧','男','18900000001');
B、限制手機列的取值型別和長度
建立觸發器,只允許phone列輸入的手機號只能是11位數字,且第一位數字是1。
create trigger trigger_limitPhone
before insert on personinfo for each row
begin
declare mesg varchar(10);if NEW.phone regexp '[1][0-9]{10}'
then set mesg='插入成功';else
select xxxx into mesg;
end if;
End
驗證觸發器,如果手機列插入的值位數不對或者第一位不是1,插入都將失敗。
insert into personinfo VALUES('唐僧','男','28900000001');
4、使用觸發器審計
使用觸發器實現對personinfo表資料操作的跟蹤,將跟蹤事件記錄到一張審計表中review。
create table review
(
username VARCHAR(20),action VARCHAR(10),
studentID CHAR(5),
sname CHAR(10),
actionTime TIMESTAMP);
A、建立觸發器記錄插入操作
create trigger trigger_insertbefore insert on personinfo for each rowbegininsert into review values(user(),'insert',new.sname,now());End
插入personinfo表一條記錄
insert into personinfo values('孫悟空','男','13008080808');
檢視review表中增加的INSERT記錄
select * from review
B、建立觸發器記錄刪除操作
create trigger trigger_delete after delete on personinfo for each row begin insert into review values(user(),'delete',old.sname,now()); end
從personinfo刪除一條記錄
delete from personinfo where sname = '孫悟空';
檢視reivew表中增加的DELETE記錄
C、建立觸發器記錄修改操作
create trigger trigger_updateafter UPDATE on personinfo for each rowbegininsert review values(user(),'update',new.sname,now());End
更新personinfo表中名字為'孫悟空'的phone。
update personinfo set phone = '189080808' where sname = '孫悟空';
檢視reivew表中增加的UPDATE記錄
喜歡的小夥伴們可以搜尋我們個人的微信公眾號“程式設計師的成長之路”點選關注或掃描下方二維碼