MySQL 存儲過程和函數

概述  

一提到存儲過程可能就會引出另外一個話題就是存儲過程的優缺點,這裏也不作討論。由於mysql中存儲過程和函數的語法很是接近因此就放在一塊兒,主要區別就是函數必須有返回值(return),而且函數的參數只有IN類型而存儲過程有IN、OUT、INOUT這三種類型。mysql

 

 

 1.建立存儲過程和函數語法

CREATE PROCEDURE sp_name ([proc_parameter[,...]])
    [characteristic ...] routine_body
 
CREATE FUNCTION sp_name ([func_parameter[,...]])
    RETURNS type
    [characteristic ...] routine_body
    
    proc_parameter:
    [ IN | OUT | INOUT ] param_name type
    
    func_parameter:
    param_name type
 
type:
    Any valid MySQL data type
 
characteristic:
    LANGUAGE SQL
  | [NOT] DETERMINISTIC
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
  | COMMENT 'string'
 
routine_body:
    Valid SQL procedure statement or statements

語法來自官方自帶的參考手冊,characteristic語法塊是須要注意的地方,先用一個例子來介紹。sql

2.示例

#建立數據庫
DROP DATABASE IF EXISTS Dpro;
CREATE  DATABASE Dpro
CHARACTER SET utf8
;

USE Dpro;

#建立部門表
DROP TABLE IF EXISTS Employee;
CREATE TABLE Employee
(id INT NOT NULL PRIMARY KEY COMMENT '主鍵',
 name VARCHAR(20) NOT NULL COMMENT '人名',
 depid INT NOT NULL COMMENT '部門id'
);

#插入測試數據
INSERT INTO Employee(id,name,depid) VALUES(1,'',100),(2,'',101),(3,'',101),(4,'',102),(5,'',103);
#建立存儲過程
DROP PROCEDURE IF EXISTS Pro_Employee; DELIMITER $$ CREATE PROCEDURE Pro_Employee(IN pdepid VARCHAR(20),OUT pcount INT ) READS SQL DATA SQL SECURITY INVOKER BEGIN SELECT COUNT(id) INTO pcount FROM Employee WHERE depid=pdepid; END$$ DELIMITER ;
#執行存儲過程 CALL Pro_Employee(
101,@pcount); SELECT @pcount;

3. 語法解釋

在建立存儲過程的時候通常都會用DELIMITER$$.....END$$ DELIMITER ;放在開頭和結束,目的就是避免mysql把存儲過程內部的";"解釋成結束符號,最後經過「DELIMITER ;」來告知存儲過程結束。數據庫

主要解釋characteristic部分:安全

LANGUAGE SQL:用來講明語句部分是SQL語句,將來可能會支持其它類型的語句。
服務器

[NOT] DETERMINISTIC:若是程序或線程老是對一樣的輸入參數產生一樣的結果,則被認爲它是「肯定的」,不然就是「非肯定」的。若是既沒有給定DETERMINISTIC也沒有給定NOT DETERMINISTIC,默認的就是NOT DETERMINISTIC(非肯定的)CONTAINS SQL:表示子程序不包含讀或寫數據的語句。less

NO SQL:表示子程序不包含SQL語句。
函數

READS SQL DATA:表示子程序包含讀數據的語句,但不包含寫數據的語句。
測試

MODIFIES SQL DATA:表示子程序包含寫數據的語句。
spa

SQL SECURITY DEFINER:表示執行存儲過程當中的程序是由建立該存儲過程的用戶的權限來執行。
線程

SQL SECURITY INVOKER:表示執行存儲過程當中的程序是由調用該存儲過程的用戶的權限來執行。(例如上面的存儲過程我寫的是由調用該存儲過程的用戶的權限來執行,當前存儲過程是用來查詢Employee表,若是我當前執行存儲過程的用戶沒有查詢Employee表的權限那麼就會返回權限不足的錯誤,若是換成DEFINER若是存儲過程是由ROOT用戶建立那麼任何一個用戶登入調用存儲過程均可以執行,由於執行存儲過程的權限變成了root)

COMMENT 'string':備註,和建立表的字段備註同樣。

注意:在編寫存儲過程和函數時建議明確指定上面characteristic部分的狀態,特別是存在複製的環境中,若是建立函數不明確指定這些狀態會報錯,從一個非複製環境將帶函數的數據庫遷移到複製環境的機器上若是沒有明確指定DETERMINISTIC, NO SQL, or READS SQL DATA該三個狀態也會報錯。

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上的行爲徹底一致。
  設置該參數能夠用動態的方式或者指定該參數來啓動數據庫服務器或者修改配置文件後重啓服務器。需注意的是,動態設置的方式會在服務器重啓後失效。
  mysql> show variables like 'log_bin_trust_function_creators';
  mysql> set global log_bin_trust_function_creators=1;
  另外若是是在master上建立函數,想經過主從複製的方式將函數複製到slave上則也需在開啓了log-bin的slave中設置上述變量的值爲ON(變量的設置不會從master複製到slave上,這點須要注意),不然主從複製會報錯。

2.明確指明函數的類型
  1 DETERMINISTIC 不肯定的
  2 NO SQL 沒有SQl語句,固然也不會修改數據
  3 READS SQL DATA 只是讀取數據,固然也不會修改數據
好比:CREATE DEFINER=`username`@`%` READS SQL DATA FUNCTION `fn_getitemclock`(i_itemid bigint,i_clock int,i_pos int) RETURNS int(11)...
這樣一來至關於明確的告知MySQL服務器這個函數不會修改數據,所以能夠在開啓了log-bin的服務器上安全的建立並被複制到開啓了log-bin的slave上。

 5.修改存儲過程函數語法

ALTER {PROCEDURE | FUNCTION} sp_name [characteristic ...]
 
characteristic:
    { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }
  | COMMENT 'string'

6.刪除存儲過程函數語法

DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name

7.查看存儲過程和函數

1.查看存儲過程狀態

 
 
SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']
show procedure status like 'Pro_Employee' \G

2.查看存儲過程和函數的建立語法

SHOW CREATE {PROCEDURE | FUNCTION} sp_name

SHOW CREATE PROCEDURE Pro_Employee \G;

3.查看存儲過程和函數詳細信息

SELECT * FROM information_schema.ROUTINES WHERE ROUTINE_NAME='Pro_Employee' \G;

總結  

 存儲過程和函數語法不難理解,可是每每存儲過程當中不僅僅只包含這種簡單的查詢語法,還會嵌套循環語句、變量、報錯處理、事務等,下一篇文章會單獨講變量,將變量的知識加入到存儲過程,包括變量的聲明和報錯處理,歡迎關注。

 

 

 

 

備註:

    做者:pursuer.chen

    博客:http://www.cnblogs.com/chenmh

本站點全部隨筆都是原創,歡迎你們轉載;但轉載時必須註明文章來源,且在文章開頭明顯處給明連接。

《歡迎交流討論》

相關文章
相關標籤/搜索