1. 程式人生 > >資料庫工作筆記012---mysql觸發器trigger 例項詳解_保證資料庫完整性還是不錯的

資料庫工作筆記012---mysql觸發器trigger 例項詳解_保證資料庫完整性還是不錯的

 mysql的觸發器,可以挺好的保證資料庫的資料的完整性,這個還是不錯的

    JAVA技術交流QQ群:170933152  

比如:

我一個表中的資料有變化,那麼與之關聯的幾個表可以通過觸發器來實現同步

--------

MySQL好像從5.0.2版本就開始支援觸發器的功能了,本次部落格就來介紹一下觸發器,首先還是談下概念性的東西吧:

什麼是觸發器

觸發器是與表有關的資料庫物件,在滿足定義條件時觸發,並執行觸發器中定義的語句集合。觸發器的這種特性可以協助應用在資料庫端確保資料的完整性。

舉個例子,比如你現在有兩個表【使用者表】和【日誌表】,當一個使用者被建立的時候,就需要在日誌表中插入建立的log日誌,如果在不使用觸發器的情況下,你需要編寫程式語言邏輯才能實現,但是如果你定義了一個觸發器,觸發器的作用就是當你在使用者表中插入一條資料的之後幫你在日誌表中插入一條日誌資訊。當然觸發器並不是只能進行插入操作,還能執行修改,刪除。

建立觸發器

建立觸發器的語法如下:

複製程式碼

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包含的多條語句
所以可以說MySQL建立以下六種觸發器:
BEFORE INSERT,BEFORE DELETE,BEFORE UPDATE
AFTER INSERT,AFTER DELETE,AFTER UPDATE

複製程式碼

其中,觸發器名引數指要建立的觸發器的名字

BEFORE和AFTER引數指定了觸發執行的時間,在事件之前或是之後

FOR EACH ROW表示任何一條記錄上的操作滿足觸發事件都會觸發該觸發器

建立有多個執行語句的觸發器

CREATE TRIGGER 觸發器名 BEFORE|AFTER 觸發事件
ON 表名 FOR EACH ROW
BEGIN
    執行語句列表
END

其中,BEGIN與END之間的執行語句列表引數表示需要執行的多個語句,不同語句用分號隔開

tips:一般情況下,mysql預設是以 ; 作為結束執行語句,與觸發器中需要的分行起衝突

     為解決此問題可用DELIMITER,如:DELIMITER ||,可以將結束符號變成||

     當觸發器建立完成後,可以用DELIMITER ;來將結束符號變成;

複製程式碼

mysql> DELIMITER ||
mysql> CREATE TRIGGER demo BEFORE DELETE
    -> ON users FOR EACH ROW
    -> BEGIN
    -> INSERT INTO logs VALUES(NOW());
    -> INSERT INTO logs VALUES(NOW());
    -> END
    -> ||
Query OK, 0 rows affected (0.06 sec)

mysql> DELIMITER ;

複製程式碼

上面的語句中,開頭將結束符號定義為||,中間定義一個觸發器,一旦有滿足條件的刪除操作

就會執行BEGIN和END中的語句,接著使用||結束

最後使用DELIMITER ; 將結束符號還原

tigger_event:

 

load data語句是將檔案的內容插入到表中,相當於是insert語句,而replace語句在一般的情況下和insert差不多,但是如果表中存在primary 或者unique索引的時候,如果插入的資料和原來的primary key或者unique相同的時候,會刪除原來的資料,然後增加一條新的資料,所以有的時候執行一條replace語句相當於執行了一條delete和insert語句。

觸發器可以是一條SQL語句,也可以是多條SQL程式碼塊,那如何建立呢?

複製程式碼

DELIMITER $  #將語句的分隔符改為$
BEGIN
sql1;
sql2;
...
sqln
END $
DELIMITER ;  #將語句的分隔符改回原來的分號";"

複製程式碼

在BEGIN...END語句中也可以定義變數,但是隻能在BEGIN...END內部使用:

DECLARE var_name var_type [DEFAULT value] #定義變數,可指定預設值
SET var_name = value  #給變數賦值

NEW和OLD的使用:

 

 根據以上的表格,可以使用一下格式來使用相應的資料:

NEW.columnname:新增行的某列資料
OLD.columnname:刪除行的某列資料

說了這麼多現在我們來建立一個觸發器吧!

現在有表如下:
使用者users表

複製程式碼

CREATE TABLE `users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL,
  `add_time` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name` (`name`(250)) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=1000001 DEFAULT CHARSET=latin1;

複製程式碼

日誌logs表:

CREATE TABLE `logs` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `log` varchar(255) DEFAULT NULL COMMENT '日誌說明',
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日誌表';

需求是:當在users中插入一條資料,就會在logs中生成一條日誌資訊。

建立觸發器:

複製程式碼

DELIMITER $
CREATE TRIGGER user_log AFTER INSERT ON users FOR EACH ROW
BEGIN
DECLARE s1 VARCHAR(40)character set utf8;
DECLARE s2 VARCHAR(20) character set utf8;#後面發現中文字元編碼出現亂碼,這裡設定字符集
SET s2 = " is created";
SET s1 = CONCAT(NEW.name,s2);     #函式CONCAT可以將字串連線
INSERT INTO logs(log) values(s1);
END $
DELIMITER ;

複製程式碼

這裡我用的navicat: 

檢視觸發器

SHOW TRIGGERS語句檢視觸發器資訊

Tip:

上面我用的navicat直接建立,如果大家用的mysql front,name這裡會有個區別,我們刪除剛才的觸發器,在Mysql front中測試
drop trigger  user_log;#刪除觸發器

開啟Mysql Front:

 

mysql front在編譯sql時,不用定義結尾分隔符,修改後的sql直接這樣既可:

複製程式碼

#DELIMITER $
CREATE TRIGGER user_log AFTER INSERT ON users FOR EACH ROW
BEGIN
DECLARE s1 VARCHAR(40)character set utf8;
DECLARE s2 VARCHAR(20) character set utf8;
SET s2 = " is created";
SET s1 = CONCAT(NEW.name,s2);     #函式CONCAT可以將字串連線
INSERT INTO logs(log) values(s1);
END #$
#DELIMITER ;

複製程式碼

這裡再囉嗦幾句:

tips:SHOW TRIGGERS語句無法查詢指定的觸發器

在triggers表中檢視觸發器資訊

SELECT * FROM information_schema.triggers;

結果顯示了所有觸發器的詳細資訊,同時,該方法可以查詢制定觸發器的詳細資訊

SELECT * FROM information_schema.triggers WHERE TRIGGER_NAME='user_log';

tips:所有觸發器資訊都儲存在information_schema資料庫下的triggers表中

     可以使用SELECT語句查詢,如果觸發器資訊過多,最好通過TRIGGER_NAME欄位指定查詢

回到上面,我們建立好了觸發器,繼續在users中插入資料並檢視資料:

insert into users(name,add_time) values('周伯通',now());

好吧,我們再來檢視一下logs表吧!

通過上面的例子,可以看到只需要在users中插入使用者的資訊,日誌會自動記錄到logs表中,這也許就是觸發器給我帶來的便捷吧!

 

限制和注意事項

觸發器會有以下兩種限制:

1.觸發程式不能呼叫將資料返回客戶端的儲存程式,也不能使用採用CALL語句的動態SQL語句,但是允許儲存程式通過引數將資料返回觸發程式,也就是儲存過程或者函式通過OUT或者INOUT型別的引數將資料返回觸發器是可以的,但是不能呼叫直接返回資料的過程。

2.不能再觸發器中使用以顯示或隱式方式開始或結束事務的語句,如START TRANS-ACTION,COMMIT或ROLLBACK。

注意事項:MySQL的觸發器是按照BEFORE觸發器、行操作、AFTER觸發器的順序執行的,其中任何一步發生錯誤都不會繼續執行剩下的操作,如果對事務表進行的操作,如果出現錯誤,那麼將會被回滾,如果是對非事務表進行操作,那麼就無法回滾了,資料可能會出錯。

 

總結

觸發器是基於行觸發的,所以刪除、新增或者修改操作可能都會啟用觸發器,所以不要編寫過於複雜的觸發器,也不要增加過得的觸發器,這樣會對資料的插入、修改或者刪除帶來比較嚴重的影響,同時也會帶來可移植性差的後果,所以在設計觸發器的時候一定要有所考慮。

觸發器是一種特殊的儲存過程,它在插入,刪除或修改特定表中的資料時觸發執行,它比資料庫本身標準的功能有更精細和更復雜的資料控制能力。

資料庫觸發器有以下的作用:

1.安全性。可以基於資料庫的值使使用者具有操作資料庫的某種權利。

  # 可以基於時間限制使用者的操作,例如不允許下班後和節假日修改資料庫資料。

  # 可以基於資料庫中的資料限制使用者的操作,例如不允許股票的價格的升幅一次超過10%。

2.審計。可以跟蹤使用者對資料庫的操作。   

  # 審計使用者操作資料庫的語句。

  # 把使用者對資料庫的更新寫入審計表。

3.實現複雜的資料完整性規則

  # 實現非標準的資料完整性檢查和約束。觸發器可產生比規則更為複雜的限制。與規則不同,觸發器可以引用列或資料庫物件。例如,觸發器可回退任何企圖吃進超過自己保證金的期貨。

  # 提供可變的預設值。

4.實現複雜的非標準的資料庫相關完整性規則。觸發器可以對資料庫中相關的表進行連環更新。例如,在auths表author_code列上的刪除觸發器可導致相應刪除在其它表中的與之匹配的行。

  # 在修改或刪除時級聯修改或刪除其它表中的與之匹配的行。

  # 在修改或刪除時把其它表中的與之匹配的行設成NULL值。

  # 在修改或刪除時把其它表中的與之匹配的行級聯設成預設值。

  # 觸發器能夠拒絕或回退那些破壞相關完整性的變化,取消試圖進行資料更新的事務。當插入一個與其主健不匹配的外部鍵時,這種觸發器會起作用。例如,可以在books.author_code 列上生成一個插入觸發器,如果新值與auths.author_code列中的某值不匹配時,插入被回退。

5.同步實時地複製表中的資料。

6.自動計算資料值,如果資料的值達到了一定的要求,則進行特定的處理。例如,如果公司的帳號上的資金低於5萬元則立即給財務人員傳送警告資料。

無論從事什麼行業,只要做好兩件事就夠了,一個是你的專業、一個是你的人品,專業決定了你的存在,人品決定了你的人脈,剩下的就是堅持,用善良專業和真誠贏取更多的信任。