MySQL觸發器(Trigger)

分類:編程 時間:2016-11-03

1 觸發器簡介

    數據庫服務器從本質上來說是被動的,我們使用一條sql語句顯示的要求它,它才會執行一個操作。觸發器就是要把一個被動的服務器編程一個主動的服務器。

    觸發器是存儲在目錄中的包含了過程式和聲明式語句的一段代碼,如果在數據庫上執行了一個特定的操作,並且只有當某一條件成立的時候,數據庫服務器才會激活它,它比數據庫本身標準的功能有更精細和更復雜的數據控制能力。

    觸發器和存儲過程在表現上有很多相似之處,即都是存儲在目錄中的一個過程式數據庫對象,都是由聲明式和過程式的sql語句組成。但它們兩個概念之間有一個重要區別,即調用方式不同,觸發器不能夠從一個程序或者存儲過程調用,沒有call或execute trigger類似的語句。mysql會自己透明的調用它,而不會被用戶意識到。

2 觸發器的優缺點
    2.1 優點

2.1.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語句 服務器 觸發器 優缺點

文章來源:


ads
ads

相關文章
ads

相關文章

ad