1. 程式人生 > >mysql學習之旅-之使用-1.2.3-之觸發器

mysql學習之旅-之使用-1.2.3-之觸發器

1、觸發器簡介
觸發器就是在執行增刪改時自行執行的sql語句,是儲存在資料庫目錄中的
2、觸發器的優缺點
優點: 
      1、減少後臺頻繁訪問資料庫
      2、安全性:可以基於資料庫的值是使用者具有操作資料庫的某種許可權,可以基於時間限制使用者操作(例不允許下班後和節假日修改資料庫資料),可以基於資料庫中的資料限制使用者的操作(例如不允許股票的價格的升幅一次超過10%)
      3、完整性:具有任務回滾的能力
      4、同步實時複製資料
缺點:
      1、如果需要變動整個資料集而資料集資料量又較大時,觸發器效果會非常低
      2、觸發器執行過程不可見,出現問題及其難查
      3、資料庫的移植性較差,維護較難        
3、觸發器的使用
A、建立觸發器

CREATE TRIGGER trigger_name trigger_time trigger_event ON tb_name FOR EACH ROW trigger_stmt

trigger_name:觸發器的名稱。
tirgger_time:觸發時機,為BEFORE或者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索引時,如果插入的資料和原來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賦值,不會再次觸發觸發器,造成迴圈呼叫。

B、刪除觸發器

DROP TRIGGER 觸發器名稱

C、檢視觸發器

SHOW TRIGGERS

4、應用
A、業務邏輯

客戶下訂單訂購商品,商品表自動減少數量。
在商品表建立刪除觸發器,刪除某商品,自動刪除該商品的訂單。
建立產品表,有產品編號,產品名稱、產品數量和產品價格四列,其中產品編號自增長列,並設定成主鍵。

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);

在這裡插入圖片描述

在訂單表上建立觸發器,當有訂單,會根據訂單的產品編號和數量自動減少產品的數量。觸發器中NEW代表一個表,存放插入的訂單記錄。

create trigger trigger_order
AFTER INSERT ON orders FOR EACH ROW
BEGIN
UPDATE product SET pnum=pnum-NEW.onum where pid = NEW.pid;
END

插入訂單

INSERT INTO orders(pid, onum)VALUES(13, 10);

檢視產品表,可以看到對應的產品數量減少。操作由訂單表的Insert觸發器完成。
在這裡插入圖片描述

在訂單表上建立新的觸發器,當訂單定的某產品產品數量大於產品庫存,禁止下訂單,也就是禁止在訂單表中插入記錄。
一張表中只能有一個INSERT型別的觸發器,先刪除INSERT觸發器。

drop trigger trigger_order;

MySQL不能在觸發器中通過回滾事務取消操作,但如果觸發器的SQL語句執行過程中出現錯誤,會自動撤銷操作,曲線實現事務回滾。

create trigger trigger_order
BEFORE INSERT ON orders FOR EACH ROW
BEGIN
DECLARE 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

   SELECT pnum INTO var FROM product where pid=NEW.pid;  用來查詢為更新前的資料賦值給 var 使用INTO

插入訂單,看看如果庫存不夠是否還能夠插入成功

INSERT INTO orders(pid, onum)VALUES(13, 110);

B、實現安全

①限制插入記錄的日期
在訂單表上建立插入觸發器,週六週日不允許下訂單(記得一個表只能有一個insert觸發器)

create trigger trigger_limitDate
BEFORE INSERT ON orders FOR EACH ROW
BEGIN
DECLARE 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)

②限制資料更改的範圍
在產品表上建立更新觸發器,限制產品價格一次上調不能超過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;

C 實現資料完整性

使用觸發器可以限制表插入某列的數值範圍。
建立一個學生表,有四列,姓名、性別、手機和郵箱。

create table personinfo
(
sname VARCHAR(5),
sex CHAR(1),
phone VARCHAR(11)
)ENGINE=innoDB default CHARSET=utf8;

①指定性別列的取值範圍
建立觸發器,限制性別列,只允許輸入“男”和“女”。before insert觸發器,不滿足條件執行有錯誤的SQL語句,退出。

create trigger trigger_limitSex
before insert on personinfo for each row
begin
declare 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’); 正確

②限制手機列的取值型別和長度
建立觸發器,只允許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’); 錯誤 (首位值)
nsert into personinfo VALUES(‘唐僧’, ‘男’,‘18900000001’); 錯誤 (值位數不對)

D使用觸發器審計

使用觸發器實現對personinfo表資料操作的跟蹤,將跟蹤事件記錄到一張審計表中review。

create table review
(
username VARCHAR(20),
action VARCHAR(10),
sname CHAR(10),
actionTime TIMESTAMP
);

①建立觸發器記錄插入操作

create trigger trigger_insert
before insert on personinfo for each row
begin
insert into review values(user(),‘insert’,new.sname,now());
End

插入personinfo表一條記錄

insert into personinfo values(‘孫悟空’, ‘男’, ‘13008080808’);

檢視review表中增加的INSERT記錄
在這裡插入圖片描述
②建立觸發器記錄刪除操作

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記錄
在這裡插入圖片描述

③建立觸發器記錄修改操作

create trigger trigger_update
after UPDATE on personinfo for each row
begin
insert review values(user(),‘update’,new.sname,now());
End

更新personinfo表中名字為‘孫悟空’的phone。

update personinfo set phone=‘189080808’ where sname='孫悟空’1;

檢視reivew表中增加的UPDATE記錄
在這裡插入圖片描述