1. 程式人生 > >MySQL5-函數/存儲過程與定時器、觸發器

MySQL5-函數/存儲過程與定時器、觸發器

名稱 狀態 訪問 safe 安全問題 ant comm gnu led

目錄 一、函數/存儲過程 二、定時器 三、觸發器 四、函數語句學習

一、函數/存儲過程

1、函數與存儲過程 (1) function與procedure的區別:一個有返回值,一個沒有,僅此而已。上述說法是錯誤的,function和procedure的用法有很多不同,總體來說procedure受到的限制較少,function的限制較多;而且procedure可以使用out參數返回值,因此盡量采用procedure。比如,以下存儲過程的創建是合法的,但函數的常見則是非法的。 #存儲過程合法 DROP PROCEDURE IF EXISTS test; CREATE PROCEDURE test()
BEGIN DECLARE i INT; SET i=1; END; #函數非法 DROP FUNCTION IF EXISTS test; CREATE FUNCTION test() BEGIN DECLARE i INT; SET i=1; END; (2)使用存儲過程/函數,比使用單獨的SQL語句要快。 2、創建函數 語法create procedure 存儲過程名字([in|out|inout] 參數 datatype) comment ‘here is zhushi‘ begin MySQL 語句; end; 參數:如果不指定in/out/inout,則默認為in;()不能省;參數前不加@;參數不能指定默認值。參數中可以使用各種類型,包括varchar,但是一定要指定長度,否則報錯。 out參數
drop procedure if exists bb; create procedure bb(out total int) begin set total = 3;#方法1:不能有@,已驗證 #方法2已驗證可以:select count(*) into total from user; end; call bb(@total); select @total;#調用語句和select語句中,都必須使用@,[email protected],[email protected] 返回值create function 存儲過程名字([in|out|inout] 參數 datatype) returns int
begin MySQL 語句; return 1; end; 註釋:comment後面跟註釋,在show procedure status中可以看到;可以省略 函數體:如果MySQL語句不止一句,則需要begin/end;每條語句都需要分號;註釋可以使用/**/、--、#;函數中可以使用return,存儲過程中不能使用。 創建函數實例drop procedure if exists pr_add;
create procedure pr_add(a int,b int) begin declare c int; if a is null then set a = 0; end if; if b is null then set b = 0; end if; set c = a + b; select c as sum; /* return c; 不能在 MySQL 存儲過程中使用。return 只能出現在函數中。*/ end; 3、delimiter:分界符;主要用在MySQL客戶端。 delimiter的作用是規定分界符;當客戶端遇到分界符時,便會執行MySQL命令。默認情況下,分界符是分號;但是在有些情景下,如定義函數,不希望遇到分號執行命令,而是等函數定義結束後執行命令,此時便使用形如delimiter $$的語句改變分界符,待函數定義結束後,再使用delimiter ;將分界符變回分號。 因此在非MySQL客戶端,如sql文件、Navicat for MySQL中執行語句時,不需要使用delimiter。 4、錯誤說明 Error Code: 1418. This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) 原因:在主從復制的兩臺MySQL服務器中開啟了二進制日誌選項log-bin,slave會從master復制數據,而一些操作,比如function所得的結果在master和slave上可能不同,所以存在潛在的安全隱患。因此,在默認情況下回阻止function的創建。   解決方案1:將log_bin_trust_function_creators參數設置為ON,這樣一來開啟了log-bin的MySQL Server便可以隨意創建function。這裏存在潛在的數據安全問題,除非明確的知道創建的function在master和slave上的行為完全一致。 查看狀態:SHOW VARIABLES LIKE ‘%log_bin_trust_function_creators%‘ 設置:set global log_bin_trust_function_creators=1【動態設置在重啟數據庫後失效;修改配置文件後重啟數據庫可以永久改變】 5、變量聲明: declare用於在函數中聲明局部變量,只在函數中有效 DECLARE variable_name1,variable_name2,…… datatype(size) DEFAULT default_value; set variable_name1 = 1;//賦值 SELECT COUNT(*) INTO total_products FROM products#另外一種賦值方式,值得註意 set @用於定義會話變量(嚴格說是用戶變量),在整個會話中都有效;不需要指定datatype,MySQL自動指定。 set @var = 1; set用於對局部變量賦值時,必須等所有的declare語句執行結束(個人懷疑是不是在函數中,所有的declare必須都放在最前面) #以下語句會報錯 drop procedure if exists test; CREATE PROCEDURE test() BEGIN DECLARE i INT; SET i = 1; DECLARE o INT; END; #以下語句則正確 drop procedure if exists test; CREATE PROCEDURE test() BEGIN DECLARE i INT; DECLARE o INT; SET i = 1; END; 6、調用函數:不能省略參數,可以使用null代替 call pr_add(10,20); 或者 set @a = 10; set @b = 20; call pr_add(@a, @b); 7、刪除函數 drop procedure if exists aa; drop precedure aa;#如果aa不存在則會錯誤 8、查看函數 show procedure/function status:查看該服務器上所有數據庫的所有procedure/function的狀態 show create procedure/function 名稱:查看指定函數的狀態 show procedure status like ‘%……%‘ 二、定時器 1、確認版本:5.1以上開始支持 select version() 2、開啟event功能:默認是關閉的 show variables like ‘event_scheduler‘ set global event_scheduler=‘on‘; 3、創建event需要的存儲過程 drop procedure if exists test_proce; create procedure test_proce() begin insert into `user`(name,age) values(‘zhoudan‘,‘18‘); end; 4、創建定時器 drop event if exists test_event; create event test_event on schedule every 1 second #執行的間隔時間 starts ‘2015-01-10 00:10:00‘ #開始執行的時間
on completion preserve disable #創建定時器後是否立即啟動,如果是disable需要手動啟動 do call test_proce(); 5、啟動、關閉、查看定時器 alter event test_event on completion preserve enable; #啟動定時器 alter event test_event on completion preserve disable; #關閉定時器 show events; #顯示本數據庫下所有定時器 6、註意:如果存儲過程執行過程中有錯誤,則整個過程中可能並不報錯,但是定時器指定的存儲過程無法正確執行。 三、觸發器 1、創建觸發器示例 create trigger newuser after insert on `user` for each row call test_proce1() 觸發器名:之前是表中唯一,現在不確定;穩妥的做法是數據庫唯一 執行時機:after/before 響應的活動:只支持insert/update/delete 關聯的表:on ‘user‘;目前MySQL只有表支持觸發器,視圖和臨時表都不支持 for each row:行級觸發器,即影響多少行就觸發多少次;與之對應的是語句觸發器,即語句執行一次出發一次;由於MySQL只支持行級觸發器,因此該語句不可省略。 執行的動作: (1)可以是單條語句,可以是begin和end包圍的多條語句,也可以支持call() (2)現在版本的動作不能返回值,如含有return語句的function,select語句等;如果包含select語句,會報錯Not allowed to return a result set from a trigger (3)動作不能對本表進行 insert ,update ,delete 操作,以免遞歸循環觸發;不僅是insert不能觸發本表的insert語句,也不能觸發本表的update和delete語句,其他同理 2、一些限制 (1)每個表對每個活動只能有兩個觸發器(一前一後),因此一個表最多可以有6個觸發器 (2)一個觸發器不能與多個事件或多個表關聯 (3)如果before觸發器執行失敗,則MySQL不會執行相應操作和after觸發器;如果操作執行失敗,則MySQL觸發器不會執行after觸發器 3、刪除與查看:觸發器不能修改或覆蓋,如果要重新定義觸發器,必須先刪除在添加 drop trigger newuser; show triggers; show create trigger ‘newuser‘; 4、insert觸發器 說明:引用名字為new的虛擬表,訪問被插入的行;一般用before進行數據驗證、凈化,用after進行日誌處理等;對於auto_increment列,new在insert之前值為0,insert之後是新的自動生成的值 before:被插入的值可以被更改;註意語法(使用普通的update語句,創建觸發器的時候沒有問題,執行插入的時候就會報錯) create trigger newuser2 before insert on `user` for each row set new.name=‘zhoubapi‘ after create trigger newuser after insert on `user` for each row insert into tmp values(new.id,new.name,new.age) 5、delete觸發器:引用名字為old的虛擬表訪問被刪除的行;old中的值全部只可讀 6、update觸發器:既可以引用old,也可以引用new;可讀性同上 四、函數語句學習 1、if if a is null then set a = 0; end if; if not exists(select 1 from ta_test where id = ‘1111‘) then #mysql語句 end if; 2、while declare i int; set i=1; while i<1000 do #mysql語句 set i = i +1; end while ; 3、錯誤處理【參考:http://blog.csdn.net/seteor/article/details/17791855】 (1)針對存儲過程 、觸發器或函數內部語句可能發生的錯誤或警告信息,需要進行相關異常的捕捉,然後作出相應的處理,異常處理的方式如下: DECLARE {CONTINUE | EXIT} HANDLER FOR {SQLSTATE sqlstate_code| MySQL error code| condition_name} handler_actions (2)Handler Type:CONTINUE | EXIT,處理類型,繼續或退出;exit只退出當前Block。 (3)Handler Condition:SQLSTATE sqlstate_code| MySQL error code| condition_name,觸發條件;其中condition_name(命名條件)既可以自己定義,也可是使用系統內置的SQLEXCEPTION、SQLWARNING和NOT FOUND。如果對於一個錯誤,同時有MySQL碼、SQLSTATE和命名條件可以捕獲,那麽只能捕獲一次錯誤,且捕獲順序是MySQL碼->SQLSTATE->命名條件。 (4)handler_actions:錯誤發生時執行的操作,在continue或exit之前執行。 (5)作用域:如果定義在begin/end之內,則begin/end之外的錯誤不會捕獲。 (6)示例:遊標與錯誤處理結合 DROP PROCEDURE IF EXISTS test; CREATE PROCEDURE test() BEGIN DECLARE no_more_record INT DEFAULT 0; DECLARE pname VARCHAR(100); DECLARE cur_record CURSOR FOR SELECT name FROM ta_tmp WHERE id < 8; DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_record = 1; OPEN cur_record; FETCH cur_record INTO pname; WHILE no_more_record != 1 DO SELECT pname; FETCH cur_record INTO pname; END WHILE; CLOSE cur_record; END; 4、臨時表【參考:http://blog.csdn.net/crazylaa/article/details/5368698】 (1)MySQL不支持數組,但是在存儲過程中,有時候需要使用復雜的運算結果,尤其是組合使用幾個表的數據時,此時可以考慮使用臨時表。 (2)臨時表:只有在當前連接情況下, TEMPORARY 表才是可見的。當連接關閉時, TEMPORARY 表被自動取消。這意味著兩個不同的連接可以使用相同的臨時表名稱,同時兩個臨時表不會互相沖突,也不與原有的同名的非臨時表沖突。 (3)基本的使用方法如下 #創建臨時表 CREATE TEMPORARY TABLE IF not exists tmpTable( user_id VARCHAR(30) primary KEY, drawingNumber int ); truncate TABLE tmpTable;#在使用前清理數據 ......#在後面的語句中可以對tmpTable進行增刪改查

MySQL5-函數/存儲過程與定時器、觸發器