mysql 存儲過程和事件總結

任務需求:定時執行的任務,調用存儲過程,進行數據遷移。

存儲過程相關總結:(存儲過程的創建 ?不能伴隨有if exists ?需要提前判斷刪除同名的存儲過程)

存儲過程的查看:

select name from mysql.proc where db = your_db_name and type = PROCEDURE

show procedure status;

查看存儲過程或函數的創建代碼

show create procedure proc_name;

存儲過程的創建 語法以及遇到的問題

MySQL中,創建存儲過程的基本形式如下:

CREATE PROCEDURE sp_name ([proc_parameter[,...]])

[characteristic ...] routine_body

其中,sp_name參數是存儲過程的名稱;proc_parameter表示存儲過程的參數列表; characteristic參數指定存儲過程的特性;routine_body參數是SQL代碼的內容,可以用BEGIN…END來標志SQL代碼的開始和結束。

proc_parameter中的每個參數由3部分組成。這3部分分別是輸入輸出類型、參數名稱和參數類型。其形式如下:

[ IN | OUT | INOUT ] param_name type

其中,IN表示輸入參數;OUT表示輸出參數; INOUT表示既可以是輸入,也可以是輸出; param_name參數是存儲過程的參數名稱;type參數指定存儲過程的參數類型,該類型可以是MySQL數據庫的任意數據類型。

characteristic參數有多個取值。其取值說明如下:

LANGUAGE SQL:說明routine_body部分是由SQL語言的語句組成,這也是數據庫系統默認的語言。

[NOT] DETERMINISTIC:指明存儲過程的執行結果是否是確定的。DETERMINISTIC表示結果是確定的。每次執行存儲過程時,相同的輸入會得到相同的輸出。NOT DETERMINISTIC表示結果是非確定的,相同的輸入可能得到不同的輸出。默認情況下,結果是非確定的。

{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }:指明子程序使用SQL語句的限制。CONTAINS SQL表示子程序包含SQL語句,但不包含讀或寫數據的語句;NO SQL表示子程序中不包含SQL語句;READS SQL DATA表示子程序中包含讀數據的語句;MODIFIES SQL DATA表示子程序中包含寫數據的語句。默認情況下,系統會指定為CONTAINS SQL。

SQL SECURITY { DEFINER | INVOKER }:指明誰有權限來執行。DEFINER表示只有定義者自己才能夠執行;INVOKER表示調用者可以執行。默認情況下,系統指定的權限是DEFINER。

COMMENT 'string':注釋信息。

技巧:創建存儲過程時,系統默認指定CONTAINS SQL,表示存儲過程中使用了SQL語句。但是,如果存儲過程中沒有使用SQL語句,最好設置為NO SQL。而且,存儲過程中最好在COMMENT部分對存儲過程進行簡單的注釋,以便以后在閱讀存儲過程的代碼時更加方便。

創建一個名為num_from_employee的存儲過程。代碼如下:

CREATE? PROCEDURE? num_from_employee (IN emp_id INT, OUT count_num INT )

READS SQL DATA

BEGIN

SELECT? COUNT(*)? INTO? count_num

FROM? employee

WHERE? d_id=emp_id ;

END

上述代碼中,存儲過程名稱為num_from_employee;輸入變量為emp_id;輸出變量為count_num。SELECT語句從employee表查詢d_id值等于emp_id的記錄,并用COUNT(*)計算d_id值相同的記錄的條數,最后將計算結果存入count_num中。代碼的執行結果如下:

mysql> DELIMITER &&

mysql> CREATE? PROCEDURE? num_from_employee

(IN emp_id INT, OUT count_num INT )

-> READS SQL DATA

-> BEGIN

-> SELECT? COUNT(*)? INTO? count_num

-> FROM? employee

-> WHERE? d_id=emp_id ;

-> END &&

Query OK, 0 rows affected (0.09 sec)

mysql> DELIMITER ;

代碼執行完畢后,沒有報出任何出錯信息就表示存儲函數已經創建成功。以后就可以調用這個存儲過程,數據庫中會執行存儲過程中的SQL語句。

說明:MySQL中默認的語句結束符為分號(;)。存儲過程中的SQL語句需要分號來? ? 結束。為了避免沖突,首先用"DELIMITER &&"將MySQL的結束符設置為&&。最后再用"DELIMITER ;"來將結束符恢復成分號。這與創建觸發器時是一樣的。

一、MySQL 創建存儲過程

“pr_add” 是個簡單的 MySQL 存儲過程,這個存儲過程有兩個 int 類型的輸入參數 “a”、“b”,返回這兩個參數的和。

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;

二、調用Mysql存儲過程

eg: call pr_add(10,20);

執行 MySQL 存儲過程,存儲過程參數為 MySQL 用戶變量。

set @a = 10;

set @b = 20;

call pr_add(@a, @b);

假定存儲過程如下:create procedure pr_return2Pr(a int,out b int,inout c int) begin set b =a; set c = a+ c; end

set @cc = 3;call pr_return2Pr(1,@bb,@cc);select @bb,@cc; 返回1,4

如果存儲過程中變量定義為out,可以不進行變量值定義,直接聲明即可。inout? 則需要提前set 變量,然后調用。

IN為默認類型,值必須在調用時指定,值不能返回(值傳遞)

OUT值可以返回(指針傳遞)

INOUT值必須在調用時指定,值可以返回

使用DECLARE來聲明,DEFAULT賦默認值,SET賦值

DECLARE counter INT DEFAULT 0;? - 默認為0

SET counter = counter+1;? ? ? ? ? ? ? - 自增+1

三、MySQL 存儲過程特點

創建 MySQL 存儲過程的簡單語法為:

create procedure 存儲過程名字()

(

[in|out|inout] 參數 datatype

)

begin

MySQL 語句;

end;

MySQL 存儲過程參數如果不顯式指定“in”、“out”、“inout”,則默認為“in”。習慣上,對于是“in” 的參數,我們都不會顯式指定。

如下,給出解釋

1. MySQL 存儲過程名字后面的“()”是必須的,即使沒有一個參數,也需要“()”

2. MySQL 存儲過程參數,不能在參數名稱前加“@”,如:“@a int”。下面的創建存儲過程語法在 MySQL 中是錯誤的(在 SQL Server 中是正確的)。 MySQL 存儲過程中的變量,不需要在變量名字前加“@”,雖然 MySQL 客戶端用戶變量要加個“@”。

create procedure pr_add

(

@a int,- 錯誤

b int? - 正確

)

3. MySQL 存儲過程的參數不能指定默認值。

4. MySQL 存儲過程不需要在 procedure body 前面加 “as”。而 SQL Server 存儲過程必須加 “as” 關鍵字。

create procedure pr_add

(

a int,

b int

)

as? ? ? ? ? ? - 錯誤,MySQL 不需要 “as”

begin

mysql statement ...;

end;

5. 如果 MySQL 存儲過程中包含單條或者多條 MySQL 語句,都需要 begin end 關鍵字。

create procedure pr_add

(

a int,

b int

)

begin

mysql statement 1 ...;

mysql statement 2 ...;

end;

6.MySQL 存儲過程中的每條語句的末尾,都要加上分號 “;”

...

declare c int;

if a is null then

set a = 0;

end if;

...

7. MySQL 存儲過程中的注釋。

/*

這是個

多行 MySQL 注釋。

/

declare c int;? ? - 這是單行 MySQL 注釋 (注意- 后至少要有一個空格)

if a is null then 這也是個單行 MySQL 注釋

set a = 0;

end if;

...

end;

8. 不能在 MySQL 存儲過程中使用 “return” 關鍵字。

set c = a + b;

select c as sum;

/*

return c;- 不能在 MySQL 存儲過程中使用。return 只能出現在函數中。

/

end;

9. 調用 MySQL 存儲過程時候,需要在過程名字后面加“()”,即使沒有一個參數,也需要“()”

call pr_no_param();

10. 因為 MySQL 存儲過程參數沒有默認值,所以在調用 MySQL 存儲過程時候,不能省略參數。可以用 null 來替代。

call pr_add(10, null);

mysql寫條件判斷時,注意時if? elseif? else? 其中elseif之間是不能夠有空格的。

命令行編寫存儲過程命令是一定注意提前delimiter。說明:MySQL中默認的語句結束符為分號(;)。存儲過程中的SQL語句需要分號來? ? 結束。為了避免沖突,首先用"DELIMITER &&"將MySQL的結束符設置為&&。最后再用"DELIMITER ;"來將結束符恢復成分號。這與創建觸發器時是一樣的。但是mysql 窗口就沒問題了。

存儲過程的刪除: 不能在一個存儲過程刪除另一個存儲過程,只能調用另一個存儲過程

drop procedure if exists prName

11,存儲方法

存儲方法與存儲過程的區別

1,存儲方法的參數列表只允許IN類型的參數,而且沒必要也不允許指定IN關鍵字

2,存儲方法返回一個單一的值,值的類型在存儲方法的頭部定義

3,存儲方法可以在SQL語句內部調用

4,存儲方法不能返回結果集

mysql事件:創建存儲過程的時候,如果采用命令行的方式,需要先修改命令結束符,將分號改成其他的符號,注意delimiter時 不能在$$后添加;? 否則就以$$;? 作為結束標記了。

-- 設置分隔符為 '$$' ,mysql默認的語句分隔符為 ';' ,這樣在后續的 create 到 end 這段代碼都會看成是一條語句來執行

DELIMITER $$

//創建存儲過程或者事件語句

//結束

$$

- 將語句分割符設置回 ';'

DELIMITER ;

事件簡介

事件(event)是MySQL在相應的時刻調用的過程式數據庫對象。一個事件可調用一次,也可周期性的啟動,它由一個特定的線程來管理的,也就是所謂的“事件調度器”。

事件和觸發器類似,都是在某些事情發生的時候啟動。當數據庫上啟動一條語句的時候,觸發器就啟動了,而事件是根據調度事件來啟動的。由于他們彼此相似,所以事件也稱為臨時性觸發器。

事件取代了原先只能由操作系統的計劃任務來執行的工作,而且MySQL的事件調度器可以精確到每秒鐘執行一個任務,而操作系統的計劃任務(如:Linux下的CRON或Windows下的任務計劃)只能精確到每分鐘執行一次。

2 事件的優缺點

2.1 優點

一些對數據定時性操作不再依賴外部程序,而直接使用數據庫本身提供的功能。

可以實現每秒鐘執行一個任務,這在一些對實時性要求較高的環境下就非常實用了。

2.2 缺點

定時觸發,不可以調用。

3 創建事件

一條create event語句創建一個事件。每個事件由兩個主要部分組成,第一部分是事件調度(event schedule),表示事件何時啟動以及按什么頻率啟動,第二部分是事件動作(event action ),這是事件啟動時執行的代碼,事件的動作包含一條SQL語句,它可能是一個簡單地insert或者update語句,也可以使一個存儲過程或者benin...end語句塊,這兩種情況允許我們執行多條SQL。

一個事件可以是活動(打開)的或停止(關閉)的,活動意味著事件調度器檢查事件動作是否必須調用,停止意味著事件的聲明存儲在目錄中,但調度器不會檢查它是否應該調用。在一個事件創建之后,它立即變為活動的,一個活動的事件可以執行一次或者多次。

3.1 創建語法如下

CREATE

[DEFINER = { user | CURRENT_USER }]

EVENT

[IF NOT EXISTS]

event_name

ON SCHEDULE schedule

[ON COMPLETION [NOT] PRESERVE]

[ENABLE | DISABLE | DISABLE ON SLAVE]

[COMMENT 'comment']

DO event_body;

schedule:

AT timestamp [+ INTERVAL interval] ...

| EVERY interval

[STARTS timestamp [+ INTERVAL interval] ...]

[ENDS timestamp [+ INTERVAL interval] ...]

interval:

quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |

WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |

DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

名詞解釋:

event_name :創建的event名字(唯一確定的)。

ON SCHEDULE:計劃任務。

schedule: 決定event的執行時間和頻率(注意時間一定要是將來的時間,過去的時間會出錯),有兩種形式 AT和EVERY。

[ON COMPLETION [NOT] PRESERVE]: 可選項,默認是ON COMPLETION NOT PRESERVE 即計劃任務執行完畢后自動drop該事件;ON COMPLETION? PRESERVE則不會drop掉。

[COMMENT 'comment'] :可選項,comment 用來描述event;相當注釋,最大長度64個字節。

[ENABLE | DISABLE] :設定event的狀態,默認ENABLE:表示系統嘗試執行這個事件, DISABLE:關閉該事情,可以用alter修改

DO event_body: 需要執行的sql語句(可以是復合語句)。CREATE EVENT在存儲過程中使用時合法的。

定時器 -- 創建定時器后會在mysql 中創建一個線程用以執行該事件。 user就是event_scheduler command-daemon state-waiting for next activation

1.查看定時器-事件調度器 MySQL事件調度器event_scheduler負責調用事件,它默認是關閉的。這個調度器不斷地監視一個事件是否要調用, 要創建事件,必須打開調度器。

show variables like '%event_scheduler%';

2.開啟時間調度器

命令行:

SET GLOBAL event_scheduler = ON;

SET @@global.event_scheduler = ON;

SET GLOBAL event_scheduler = 1;

SET @@global.event_scheduler = 1;

配置文件:event_scheduler = 1 #或者ON

查看調度器線程

mysql> show processlist;

+----+-----------------+-----------+------+---------+------+------------------------+------------------+

| Id | User? ? ? ? ? ? | Host? ? ? | db? | Command | Time | State? ? ? ? ? ? ? ? ? | Info? ? ? ? ? ? |

+----+-----------------+-----------+------+---------+------+------------------------+------------------+

|? 2 | root? ? ? ? ? ? | localhost | NULL | Query? |? ? 0 | NULL? ? ? ? ? ? ? ? ? | show processlist |

|? 3 | event_scheduler | localhost | NULL | Daemon? |? ? 6 | Waiting on empty queue | NULL? ? ? ? ? ? |

+----+-----------------+-----------+------+---------+------+------------------------+------------------+

關閉事件調度器

通過命令行

可通過如下任何一個命令行

SET GLOBAL event_scheduler = OFF;

SET @@global.event_scheduler = OFF;

SET GLOBAL event_scheduler = 0;

SET @@global.event_scheduler = 0;

通過配置文件my.cnf

在[mysqld]下增加

event_scheduler = 0 #或者OFF,DISABLED

查看調度器線程

mysql> show processlist;

+----+------+-----------+------+---------+------+-------+------------------+

| Id | User | Host? ? ? | db? | Command | Time | State | Info? ? ? ? ? ? |

+----+------+-----------+------+---------+------+-------+------------------+

|? 2 | root | localhost | NULL | Query? |? ? 0 | NULL? | show processlist |

+----+------+-----------+------+---------+------+-------+------------------+

查看事件運行狀態:

(1)查詢mysql.event表;

(2)通過SHOW EVENTS命令;

(4)通過查詢information_schema.events表

(5)SHOW CREATE EVENT。 -- 查看創建目錄

總之,event的使用頻率較低建議使用root用戶進行創建和維護。

使用權限

單獨使用event調用SQL語句時,查看和創建需要用戶具有event權限,調用該SQL語句時,需要用戶具有執行該SQL的權限。Event權限的設置保存在mysql.user表和mysql.db表的Event_priv字段中。

當event和procedure配合使用的時候,查看和創建存儲過程需要用戶具有create routine權限,調用存儲過程執行時需要使用excute權限,存儲過程調用具體的SQL語句時,需要用戶具有執行該SQL的權限。

關于事件計劃的權限:

單獨使用event調用SQL語句時,查看和創建需要用戶具有event權限,調用該SQL語句時,需要用戶具有執行該SQL的權限。Event權限的設置保存在mysql.user表和mysql.db表的Event_priv字段中。(FLUSH PRIVILEGES;)

當event和procedure配合使用的時候,查看和創建存儲過程需要用戶具有create routine權限,調用存儲過程執行時需要使用excute權限,存儲過程調用具體的SQL語句時,需要用戶具有執行該SQL的權限。

SELECT HOST,USER,Event_priv FROM mysql.user;

(Figure1:user表的Event_priv權限)

獲取當前登陸的用戶和數據庫:SELECT CURRENT_USER(), SCHEMA();

從Figure1可以知道bfsql@%是沒有Event_priv權限的,在該用戶下創建事件的時候會出現下面的錯誤:

Error Code: 1044

Access denied for user 'bfsql'@'%' to database 'blog'

如果出現上面的錯誤,執行下面的SQL就可以給bfsql@%賦予創建Event的權限:

UPDATE mysql.user SET Event_priv = 'Y' WHERE HOST='%' AND USER='bfsql';

如果你這個時候再次執行創建Event的SQL,還是會出現上面的錯誤,因為你需要執行:

FLUSH PRIVILEGES;最后,你可以通過SHOW GRANTS FOR 'bfsql'@'%';查看所有權限;

創建event語句相關命令解釋:

ON SCHEDULE 計劃任務,有兩種設定計劃任務的方式:

1. AT 時間戳,用來完成單次的計劃任務。

2. EVERY 時間(單位)的數量時間單位[STARTS 時間戳] [ENDS時間戳],用來完成重復的計劃任務。

在兩種計劃任務中,時間戳可以是任意的TIMESTAMP 和DATETIME 數據類型,時間戳需要大于當前時間。

在重復的計劃任務中,時間(單位)的數量可以是任意非空(Not Null)的整數式,時間單位是關鍵詞:YEAR,MONTH,DAY,HOUR,MINUTE 或者SECOND。

提示: 其他的時間單位也是合法的如:QUARTER, WEEK, YEAR_MONTH,DAY_HOUR,DAY_MINUTE,DAY_SECOND,HOUR_MINUTE,HOUR_SECOND, MINUTE_SECOND,不建議使用這些不標準的時間單位。

標注4: [ON COMPLETION [NOT] PRESERVE]

ON COMPLETION參數表示"當這個事件不會再發生的時候",即當單次計劃任務執行完畢后或當重復性的計劃任務執行到了ENDS階段。而PRESERVE的作用是使事件在執行完畢后不會被Drop掉,建議使用該參數,以便于查看EVENT具體信息。

標注5:[ENABLE | DISABLE]

參數Enable和Disable表示設定事件的狀態。Enable表示系統將執行這個事件。Disable表示系統不執行該事件。

可以用如下命令關閉或開啟事件:

ALTER EVENT event_name? ENABLE/DISABLE

標注6:[COMMENT 'comment']

注釋會出現在元數據中,它存儲在information_schema表的COMMENT列,最大長度為64個字節。'comment'表示將注釋內容放在單引號之間,建議使用注釋以表達更全面的信息。

當然SQL語句是有限制的,對它的限制跟函數Function和觸發器Trigger 中對SQL語句的限制是一樣的,如果你在函數Function 和觸發器Trigger 中不能使用某些SQL,同樣的在EVENT中也不能使用。明確的來說有下面幾個:

LOCK TABLES

UNLOCK TABLES

CREATE EVENT

ALTER EVENT

LOAD DATA

修改事件 使用ALTER EVENT 來修改事件,具體的ALTER語法如下,與創建事件的語法類似:

刪除事件:EVENT使用DROP EVENT語句來刪除已經創建的事件,語法如下:DROP EVENT [IF EXISTS] event_name

但當一個事件正在運行中時,刪除該事件不會導致事件停止,事件會執行到完畢為止。使用DROP USER和DROP DATABASE 語句同時會將包含其中的事件刪除。

每隔一秒自動調用e_test()存儲過程:

CREATE EVENT IF NOT EXISTS e_test

ON SCHEDULE EVERY 1 SECOND

ON COMPLETION PRESERVE

DO CALL e_test();

每個月的一號凌晨1 點執行STAT()存儲過程:

CREATE? EVENT? NOT EXISTS? STAT

ON? SCHEDULE? EVERY? 1? MONTH? STARTS DATE_ADD(DATE_ADD(DATE_SUB(CURDATE(),INTERVAL DAY(CURDATE())-1 DAY), INTERVAL 1 MONTH),INTERVAL 1 HOUR)

ON? COMPLETION? PRESERVE? ENABLE

DO

BEGIN

CALL STAT();

END

創建一個每隔3秒往test表中插入一條數據的事件,代碼如下:

CREATE EVENT IF NOT EXISTS test ON SCHEDULE EVERY 3 SECOND

ON COMPLETION PRESERVE

DO INSERT INTO test(id,t1) VALUES('',NOW());

創建一個10分鐘后清空test表數據的事件

CREATE EVENT IF NOT EXISTS test

ON SCHEDULE

AT CURRENT_TIMESTAMP + INTERVAL 10 MINUTE

DO TRUNCATE TABLE test.aaa;

創建一個在2012-08-23 00:00:00時刻清空test表數據的事件

CREATE EVENT IF NOT EXISTS test

ON SCHEDULE

AT TIMESTAMP '2012-08-23 00:00:00'

DO TRUNCATE TABLE test;

創建一個從2012年8月22日21點45分開始到10分鐘后結束,運行每隔3秒往test表中插入一條數據的事件

CREATE EVENT IF NOT EXISTS test ON SCHEDULE EVERY 3 SECOND

STARTS '2012-08-22 21:49:00'

ENDS '2012-08-22 21:49:00'+ INTERVAL? 10 MINUTE

ON COMPLETION PRESERVE

DO INSERT INTO test(id,t1) VALUES('',NOW());

注意:

默認創建事件存儲在當前庫中,也可顯示指定事件創建在哪個庫中

通過show events只能查看當前庫中創建的事件

事件執行完即釋放,如立即執行事件,執行完后,事件便自動刪除,多次調用事件或等待執行事件可以查看到。

如果兩個事件需要在同一時刻調用,mysql會確定調用他們的順序,如果要指定順序,需要確保一個事件至少在另一個事件1秒后執行

對于遞歸調度的事件,結束日期不能在開始日期之前。

select可以包含在一個事件中,然而他的結果消失了,就好像沒執行過。

刪除事件:drop event 語句刪除它。使用這條語句我們不需要等到最后一次事件調用。DROP EVENT [IF EXISTS] event_name,drop event if exists event_second;

一個事件示例:每分鐘的零秒執行數據遷移

create event updateEachMinuteAt0Second

on schedule every 1 minute starts timestampadd(second,60 -second(current_timestamp()),current_timestamp())

on completion preserve enable

do

begin

call updatetestevent();

end


函數體內使用函數變量提前聲明 declare a int; ? 判斷是否為空 ? a is null; ?條件塊:if ?body then body; elseif body then body; end if; ? ? ? ? ? ? ? 存儲過程:begin ?body ?end;

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 當一個大型系統在建立時,會發現,很多的SQL操作是有重疊的,個別計算是相同的,比如:業務系統中,計算一張工單的計算...
    JackFrost_fuzhu閱讀 3,447評論 0 27
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,764評論 18 399
  • 轉載自這里 存儲過程簡介 我們常用的操作數據庫語言SQL語句在執行的時候需要要先編譯,然后執行,而存儲過程(Sto...
    杜七閱讀 2,421評論 4 27
  • 定義函數的方式有兩種:一種是函數聲明,另一種是函數表達式。函數聲明的語法是這樣的。 說明:Firefox、Safa...
    yjaal閱讀 220評論 0 1
  • (1) 昨天晚間忽然偏頭痛發作。許是著了涼,也可能是拿手機看書刺激了眼神經。以前辦公室內空氣不流通時也會引發。總之...
    Asura_Shi閱讀 265評論 0 0