1 存儲過程簡介
存儲過程是一段代碼,由存儲在一個數據庫的目錄中、聲明式的和過程式的sql語句組成,可以從一個程序、觸發器或者另一個存儲過程調用它從而激活它。存儲過程(Stored Procedure)是一組爲了完成特定功能的SQL語句集,經編譯後存儲在數據庫中,用戶通過指定存儲過程的名字並給定參數(如果該存儲過程帶有參數)來調用執行它。
一個存儲過程是一個可編程的函數,它在數據庫中創建並保存。它可以有SQL語句和一些特殊的控制結構組成。當希望在不同的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是非常有用的。數據庫中的存儲過程可以看做是對編程中面向對象方法的模擬。它允許控制數據的訪問方式。
2 存儲過程優缺點
2.1 優點
2.1.1 執行速度更快。有兩個原因:首先,在存儲過程創建的時候,數據庫已經對其進行了一次解析和優化,它只在創造時進行編譯,以後每次執行存儲過程都不需再重新編譯,而一般 SQL 語句每執行一次就編譯一次,所以使用存儲過程可提高數據庫執行速度。其次,存儲過程一旦執行,在內存中就會保留一份這個存儲過程,這樣下次再執行同樣的存儲過程時,可以從內存中直接調用。
2.1.2 減少網絡通信量。調用一個SQL語句不多的存儲過程與直接調用SQL語句的網絡通信量可能不會有很大的差別,但如果存儲過程包含較多SQL語句,那麼其性能絕對比一條一條的調用SQL語句要高得多。
2.1.3 安全性高。可設定只有某此用戶才具有對指定存儲過程的使用權。
2.1.4 可維護性高。更新存儲過程通常比更改、測試以及重新部署程序集需要較少的時間和精力。
2.1.5 不依賴某種宿主語言。如果用多種語言開發,某些通用代碼不用重複。
2.1.6 布式工作。應用程序和數據庫的編碼工作可以分別獨立進行,而不會相互壓制。
2.1.7 存儲過程可以重複使用,可減少數據庫開發人員的工作量。
2.2 缺點
2.2.1 SQL本身是一種結構化查詢語言,加上了一些控制(賦值、循環和異常處理等),本質上還是過程化的,面對複雜的業務邏輯,過程化的處理會很吃力。這一點算致命傷。
2.2.2 不便於調試。基本上沒有較好的調試器,很多時候是用print來調試,但用這種方法調試長達數百行的存儲過程簡直是噩夢。
2.2.3 無法適應數據庫的切割(水平或垂直切割)。數據庫切割之後,存儲過程並不清楚數據存儲在哪個數據庫中。
2.2.4 精通SQL的新手越來越少。
3 創建存儲過程
3.1 創建語法如下
CREATE PROCEDURE存儲過程名 (參數列表) BEGIN SQL語句代碼塊 END3.2 例如:計算兩個數之和
delimiter // create procedure procedureAdd (a int, IN 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; end; // delimiter ;3.3 注意:
由括號包圍的參數列必須總是存在。如果沒有參數,也該使用一個空參數列()。每個參數默認都是一個IN參數,要指定爲其它參數,可在參數名之前使用關鍵詞 OUT或INOUT
在mysql客戶端定義存儲過程的時候使用delimiter命令來把語句定界符從;變爲//,創建完之後在將分隔符更改爲;號。
4 查看存儲過程
查看數據庫中所有存儲的存儲過程基本信息,包括所屬數據庫,存儲過程名稱,創建時間等。
show procedure status \G
或者
select name from mysql.proc where db = 'your_db_name' and 'type' = 'PROCEDURE';
查看某個已存在的存儲過程的詳細信息(其中procedureAdd爲以創建的存儲過程名)
show create procedure procedureAdd \G
5 調用存儲過程
5.1 基本語法
call 存儲過程名(參數列表)
5.2 例如call procedureAdd(10, 30);
或者
set @a = 10; set @b = 30; call procedureAdd(@a, @b);注意:在使用SET定義變量時應遵循SET的語法規則 SET @變量名=初始值;
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)
轉載請註明出處:http://blog.csdn.net/jesseyoung/article/details/34420839