1 觸發器簡介
數據庫服務器從本質上來說是被動的,我們使用一條sql語句顯示的要求它,它才會執行一個操作。觸發器就是要把一個被動的服務器編程一個主動的服務器。
觸發器是存儲在目錄中的包含了過程式和聲明式語句的一段代碼,如果在數據庫上執行了一個特定的操作,並且只有當某一條件成立的時候,數據庫服務器才會激活它,它比數據庫本身標準的功能有更精細和更復雜的數據控制能力。
觸發器和存儲過程在表現上有很多相似之處,即都是存儲在目錄中的一個過程式數據庫對象,都是由聲明式和過程式的sql語句組成。但它們兩個概念之間有一個重要區別,即調用方式不同,觸發器不能夠從一個程序或者存儲過程調用,沒有call或execute trigger類似的語句。mysql會自己透明的調用它,而不會被用戶意識到。
2 觸發器的優缺點
2.1 優點
2.1.2 安全。不會有SQL語句註入問題存在,可以基於數據庫的值限制用戶操作數據庫的某種權利。
如:可以基於時間限制用戶的操作,例如不允許下班後和節假日修改數據庫數據。
可以基於數據庫中的數據限制用戶的操作,例如不允許股票的價格的升幅一次超過10%。
2.1.3 審計。可以跟蹤用戶對數據庫的操作。
如:審計用戶操作數據庫的語句。
把用戶對數據庫的更新寫入審計表。
2.1.4 業務邏輯封裝性好,修改方便。
2.1.5 數據完整性。
2.1.5.1實現復雜的數據完整性規則
實現非標準的數據完整性檢查和約束。觸發器可產生比規則更為復雜的限制。與規則不同,觸發器可以引用列或數據庫對象。例如,觸發器可回退任何企圖吃進超過自己保證金的期貨。
提供可變的缺省值。
2.1.5.2實現復雜的非標準的數據庫相關完整性規則。觸發器可以對數據庫中相關的表進行連環更新。
觸發器能夠拒絕或回退那些破壞相關完整性的變化,取消試圖進行數據更新的事務。如對5張表進行更新,更新到兩張表時數據庫服務器宕機,重啟後會自動回退。
2.2 缺點
2.2.1 可移植性差。
2.2.2 定時觸發,不可以調用。
2.2.3 當數據庫之間數據導出導入的時候, 可能會引起不必要的觸發邏輯。
2.2.4 精通SQL的新手越來越少。
3 創建觸發器
3.1 創建語法如下
CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_nameFOR EACH ROWtrigger_stmt
其中:trigger_time是觸發程序的動作時間。它可以是BEFORE或AFTER,以指明觸發程序是在激活它的語句之前或之後觸發。
trigger_event指明了激活觸發程序的語句的類型。它可以是INSERT,update或DELETE
trigger_stmt是當觸發程序激活時執行的語句。如果你打算執行多個語句,可使用BEGIN ... END復
合語句結構。
create trigger <觸發器名稱>{ before | after} {insert | update | delete} on <表名>for each row<觸發器SQL語句>
註意:由上述可見,可以建立6種觸發器,即:BEFORE INSERT、BEFORE UPDATE、BEFORE DELETE、AFTER INSERT、AFTER UPDATE、AFTER DELETE。
另外有一個限制是不能同時在一個表上建立2個相同類型的觸發器,因此在一個表上最多建立6個觸發器。
3.2 例如:兩張表聯合更新
創建測試表1
drop table if exists tab_first;create table tab_first(tab_first_id varchar(11));
創建測試表2
drop table if exists tab_sec;create table tab_sec(tab_sec_id varchar(11));創建觸發器
drop trigger if exists tri_afterinsert_tab_first;delimiter //create trigger tri_afterinsert_tab_firstafter insert on tab_firstfor each rowbegin insert into tab_sec(tab_sec_id) values (new.tab_first_id);end//delimiter ;3.3 註意: 觸發器可以調用存儲過程。
4 查看觸發器
查看數據庫中所有存儲的觸發器基本信息,包括所屬數據庫,觸發器名稱,創建時間,創建語句等。
show triggers /G或者
SELECT * FROM information_schema.triggers WHERE trigger_name='tri_afterinsert_tab_first' /G
5 觸發 觸發器
5.1 觸發方式
滿足觸發器所預定的觸發條件,觸發器即可被觸發。
5.2 例如,增加tab_first表記錄後自動將相應記錄增加到tab_sec表中
mysql> insert into tab_first(tab_first_id) values ("test1");mysql> select * from tab_first;+--------------+| tab_first_id |+--------------+| test1 |+--------------+mysql> select * from tab_sec;+------------+| tab_sec_id |+------------+| test1 |+------------+
註意:
6 修改存儲過程
6.1 基本語法
ALTER PROCEDURE 存儲過程名 [characteristic ...]註意:characteristic是存儲過程創建時的特征,在CREATE PROCEDURE語句中已經介紹過。只要設定了其中的值,存儲過程的特征就隨之變化。
如果要修改存儲過程的內容,可以使用先刪除再重新定義存儲過程的方法。存儲過程某些的特征如下
characteristic:
COMMENT 'string'
| LANGUAGE SQL
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
6.2 例如:修改特征
查看默認特征值
mysql> SELECT SPECIFIC_NAME,SQL_DATA_ACCESS, ROUTINE_COMMENT FROM information_schema.Routines WHERE ROUTINE_NAME='procedureAdd';+---------------+-----------------+-----------------+| SPECIFIC_NAME | SQL_DATA_ACCESS | ROUTINE_COMMENT |+---------------+-----------------+-----------------+| procedureAdd | CONTAINS SQL | |+---------------+-----------------+-----------------+將讀寫權限改為READS SQL DATA,並加上註釋信息'This is a test!',代碼執行如下:
mysql> ALTER PROCEDURE procedureAdd READS SQL DATA COMMENT 'This is a test!';查看修改後的特征值
mysql> SELECT SPECIFIC_NAME,SQL_DATA_ACCESS, ROUTINE_COMMENT FROM information_schema.Routines WHERE ROUTINE_NAME='procedureAdd';+---------------+-----------------+-----------------+| SPECIFIC_NAME | SQL_DATA_ACCESS | ROUTINE_COMMENT |+---------------+-----------------+-----------------+| procedureAdd | READS SQL DATA | This is a test! |+---------------+-----------------+-----------------+說明:從查詢的結果可以看出,訪問數據的權限(SQL_DATA_ACCESS)已經變成READS SQL DATA,函數註釋(ROUTINE_COMMENT)已經變成了"This is a test!"。
7 刪除存儲過程
7.1 基本語法
DROP PROCEDURE IF EXISTS 存儲過程名7.2 例如
DROP PROCEDURE IF EXISTS procedureAdd;
註意:不能在一個存儲過程中刪除另一個存儲過程,只能調用另一個存儲過程。
***************************************************************************************************************************************************************
8 存儲過程局部變量
8.1 介紹
在一個存儲過程內部,可以聲明局部變量。他們可以用來存儲中間臨時結果。如果我們在一個存儲過程中需要一個局部變量,必須使用DECLARE VARIABLE語句引入它。通過聲明,就確定了變量的數據類型,並且也可以指定初始值。(如果使用了DECLARE VARIABLE語句,他們必須作為BEGIN-END語句塊的第一條語句包含其中)
8.2 例如:
delimiter //create procedure test(out num1 integer) begin declare num2 integer default 100; set num1 = num2; end//delimiter ;調用存儲過程
call test(@num);select @num;9 存儲過程和用戶變量
9.1 介紹
用戶變量總有一個全局特性,即便它在一個存儲過程內部創建,在存儲過程結束後他們依然保留。在存儲過程之外創建的用戶變量,仍然可以在存儲過程中保留他們自己的值。
9.2 例如
delimiter //create procedure user_variable() begin set @varTest = 1; end//delimiter ;調用存儲過程後查看varTest值為1
call user_variable();select @varTest;說明:set語句是sql本身的一部分,它可以講一個值賦給用戶變量和局部變量,也可使用任何隨機表達式。
10 存儲過程與遊標
10.1 介紹
常規的select語句可能返回多行,使用遊標(cursor)可以處理這一點,把數據一行一行的取入到存儲過程中。使用遊標需要用到四個特殊語句:declare sursor,open sursor,fetch cursor,和close cursor。
如果使用declare cursor語句聲明一個遊標,我們就把它連接到了一個表表達式。接下來就可以使用fetch cursor語句來把產生的結果一行一行的獲取到存儲過程中。在某個時刻,結果中只有一行可見,也就是當前行。它就好像是指向結果中一行的一個箭頭,這也是遊標這個名字的來歷。使用fetch cursor這條語句,我們可以把遊標移動到下一行,當處理完所有的行,可以使用close cursor語句來刪除結果。
10.2 遊標作用及屬性
作用:
就是用於對查詢數據庫所返回的記錄進行遍歷,以便進行相應的操作;
屬性:
遊標是只讀的,也就是不能更新它;
遊標是不能滾動的,也就是只能在一個方向上進行遍歷,不能在記錄之間隨意進退,不能跳過某些記錄;
避免在已經打開遊標的表上更新數據。
10.3 如何使用遊標
聲明遊標
DECLARE cursor_name CURSOR FOR SELECT語句;
打開遊標
OPEN cursor_name;
移動遊標
FETCH cursor_name INTO variable list;
關閉遊標
CLOSE cursor_name;
10.4 遊標實例
創建測試表及數據
CREATE TABLE test.users ( ID bigint(20) unsigned NOT NULL AUTO_INCREMENT, user_name varchar(60) NOT NULL DEFAULT '', user_pass varchar(64) NOT NULL DEFAULT '', PRIMARY KEY (ID) )ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
insert into test.users values(1,'name1', 'pass1');insert into test.users values(2,'name2', 'pass2');insert into test.users values(3,'name3', 'pass3');insert into test.users values(4,'name4', 'pass4');insert into test.users values(5,'name5', 'pass5');
創建遊標存儲過程
delimiter |create procedure test_cursor (in param int(10),out result varchar(90))begin declare name varchar(20); declare pass varchar(20); declare done int; declare cur_test CURSOR for select user_name,user_pass from test.users; declare continue handler FOR SQLSTATE '02000' SET done = 1; if param then select concat_ws(',',user_name,user_pass) into result from test.users where id=param; else open cur_test; repeat fetch cur_test into name, pass; select concat_ws(',',result,name,pass) into result; until done end repeat; close cur_test; end if;end;|delimiter ;
各行命令詳解
1行,告訴MySQL解釋器,輸入結束命令改為|,默認為;(命令本身與存儲過程無關) 2行,創建一個存儲過程,註意:如果我把out result varchar(90)改成out result varchar,返回的結果中只有一個字符。 3行,開始 4行,定義一個變量name 5行,定義變量pass 6行,定義一個結束標識 7行,定義一個光標,指向select user_name,user_pass from test.users;語句 8行,如果sqlstate等於02000時,把done設置成1,也就是找不到數據時 9,11,18行,if判斷 10行,根據參數,把數據取出來,放到result中,concat_ws函數表示concat with separator,即有分隔符的字符串連接,如連接後以逗號分隔 12行,打開光標 13,16行,repeat循環,根php的do while原理一樣 14行,從光標中取出數據。 15行,將數據合並起來 17行,關閉光標 18,19行,標簽閉合。 20行,
結果反饋
mysql> call test_cursor(3,@test); Query OK, 1 row affected (0.00 sec)mysql> select @test;+-------------+| @test |+-------------+| name3,pass3 |+-------------+1 row in set (0.00 sec)mysql> call test_cursor('',@test);Query OK, 1 row affected, 2 warnings (0.00 sec)mysql> select @test;+-------------------------------------------------------------------------+| @test |+-------------------------------------------------------------------------+| name1,pass1,name2,pass2,name3,pass3,name4,pass4,name5,pass5,name5,pass5 |+-------------------------------------------------------------------------+1 row in set (0.00 sec)
<關鍵字:trigger delimiter>
轉載請註明出處:http://blog.csdn.net/jesseyoung/article/details/34826721
Tags: 數據庫數據 sql語句 服務器 觸發器 優缺點
文章來源: