存儲過程是在大型數據庫系統中一組為了完成特定功能的SQL語句集,存儲在數據庫中。存儲過程經過第一次編譯后,再次調用不需要編譯,用戶可以通過指定的存儲過程名和給出一些存儲過程定義的參數來使用它。一般用的較少。和腳本有類似之處。
(1).存儲過程的優缺點
優點:
1.增強SQL語言的功能和靈活性:存儲過程可以用控制語句編寫,有很強的靈活性,可以完成復雜的判斷和較復雜的運算。
2標准組件式編程:存儲過程被創建后,可以在程序中被多次調用,而不必重新編寫該存儲過程的SQL語句。而且數據庫專業人員可以隨時對存儲過程進行修改,對應用程序源代碼毫無影響。
3.較快的執行速度:如果某一操作包含大量的Transaction-SQL代碼或分別被多次執行,那么存儲過程要比批處理的執行速度快很多。因為存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,並且給出最終被存儲在系統表中的執行計划。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。
4.減少網絡流量:針對同一個數據庫對象的操作(如查詢、修改),如果這一操作所涉及的Transaction-SQL語句被組織進存儲過程,那么當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大減少網絡流量並降低了網絡負載。
5.作為一種安全機制來充分利用:通過對執行某一存儲過程的權限進行限制,能夠實現對相應的數據的訪問權限的限制,避免了非授權用戶對數據的訪問,保證了數據的安全。
缺點:
1.可移植性差
2.對於簡單的SQL語句,存儲過程沒什么優勢
3.如果存儲過程中不一定會減少網絡傳輸
4.如果只有一個用戶使用數據庫,那么存儲過程對安全也沒什么影響
5.團隊開發時需要先統一標准,否則后期維護成本大
6.在大並發量訪問的情況下,不宜寫過多涉及運算的存儲過程
7.業務邏輯復雜時,特別是涉及到對很大的表進行操作的時候,不如在前端先簡化業務邏輯
(2).創建存儲過程
創建測試環境
mysql> create database test_db; Query OK, 1 row affected (0.00 sec) mysql> use test_db; Database changed mysql> create table user_tb(id int,name varchar(20)); Query OK, 0 rows affected (0.02 sec) mysql> insert into user_tb values(1,'學生'),(2,'老師'),(3,'校長'); Query OK, 3 rows affected (0.04 sec) Records: 3 Duplicates: 0 Warnings: 0
創建存儲過程語句格式
create procedure [過程名]([in|out|inout] [參數名] [參數類型],...) begin [SQL語句集;] end
注意:由於SQL語句集部分一樣使用的是分號(;)作為分隔符,所以要在創建存儲過程前使用delimiter重新定義分隔符。delimiter [新分隔符];
在定義參數部分時in表示傳入參數,讀取外部變量值賦給內部參數,但內部參數的作用域僅限存儲過程;out表示傳出參數,將內部參數傳遞到外部變量;inout既有in的功能,又用out的功能,屬於in與out的結合體。在都不寫的情況下,默認使用in選項。
實例:
mysql> delimiter // mysql> create procedure select1() -> begin -> select * from user_tb; -> end // Query OK, 0 rows affected (0.05 sec) mysql> create procedure select2(inout id_inout int) -> begin -> select * from user_tb where id=id_inout; -> set id_inout=2; -> end // Query OK, 0 rows affected (0.00 sec) mysql> delimiter ;
另外SQL語句集還可以包含--單行注釋和/*...*/多行注釋。
(3).調用存儲過程
調用存儲過程很簡單,就是call [過程名](@[外部參數名],...)
實例:
mysql> call select1(); //調用存儲過程select1 +------+--------+ | id | name | +------+--------+ | 1 | 學生 | | 2 | 老師 | | 3 | 校長 | +------+--------+ 3 rows in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> set @id=1; //設置一個局部變量 Query OK, 0 rows affected (0.00 sec) mysql> call select2(@id); //調用存儲過程select2 +------+--------+ | id | name | +------+--------+ | 1 | 學生 | +------+--------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> select @id; //可以看到@id的值變化了 +------+ | @id | +------+ | 2 | +------+ 1 row in set (0.00 sec)
(4).查看存儲過程
查看所有的存儲過程
mysql> select name from mysql.proc where type='PROCEDURE'; +-------------------------------------+ | name | +-------------------------------------+ | create_synonym_db | | diagnostics | | execute_prepared_stmt | | ps_setup_disable_background_threads | | ps_setup_disable_consumer | | ps_setup_disable_instrument | | ps_setup_disable_thread | | ps_setup_enable_background_threads | | ps_setup_enable_consumer | | ps_setup_enable_instrument | | ps_setup_enable_thread | | ps_setup_reload_saved | | ps_setup_reset_to_default | | ps_setup_save | | ps_setup_show_disabled | | ps_setup_show_disabled_consumers | | ps_setup_show_disabled_instruments | | ps_setup_show_enabled | | ps_setup_show_enabled_consumers | | ps_setup_show_enabled_instruments | | ps_statement_avg_latency_histogram | | ps_trace_statement_digest | | ps_trace_thread | | ps_truncate_all_tables | | statement_performance_analyzer | | table_exists | | select1 | | select2 | +-------------------------------------+ 28 rows in set (0.00 sec)
當然也可以指定數據庫名來縮小范圍
mysql> select name from mysql.proc where db='test_db' and type='PROCEDURE'; +---------+ | name | +---------+ | select1 | | select2 | +---------+ 2 rows in set (0.00 sec)
查看存儲過程中的具體內容
mysql> show create procedure test_db.select1\G *************************** 1. row *************************** Procedure: select1 sql_mode: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION Create Procedure: CREATE DEFINER=`root`@`localhost` PROCEDURE `select1`() begin select * from user_tb; end character_set_client: utf8 collation_connection: utf8_general_ci Database Collation: utf8_general_ci 1 row in set (0.00 sec)
查看存儲過程的狀態,不建議使用,因為一次輸出太多了
mysql> show procedure status\G
(5).修改存儲過程
想要修改存儲過程,要么刪除重建,要么使用第三方工具修改
(6).刪除存儲過程
drop procedure [過程名];
mysql> drop procedure select2; Query OK, 0 rows affected (0.00 sec) mysql> select `name` from mysql.proc where db='test_db' and `type`='PROCEDURE'; +---------+ | name | +---------+ | select1 | +---------+ 1 row in set (0.00 sec)
(7).SQL語句集的高級用法
1)定義存儲過程的內部變量
定義變量語句:declare [變量名,...] [變量類型] [default 默認值];
賦值語句:set [變量名]=[表達式];
可以一次定義多個同類型的變量,並且設置初始值。
2)多層嵌套
這里寫一個實例
mysql> delimiter // mysql> create procedure select3() -> begin -> declare name varchar(20) default '學生'; -> select name; -> begin -> declare name varchar(20) default '老師'; -> select name; -> end; -> end // Query OK, 0 rows affected (0.00 sec) mysql> delimiter ; mysql> call select3(); +--------+ | name | +--------+ | 學生 | +--------+ 1 row in set (0.00 sec) +--------+ | name | +--------+ | 老師 | +--------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec)
3)條件語句
if語句
if [判斷語句] then [執行內容] end if; if [判斷語句] then [執行內容] else [執行內容] end if;
if語句實例:
mysql> delimiter // mysql> create procedure `if`(in num int) -> begin -> declare a int; -> set a=num; -> if a>0 then -> set a=a+1; -> else -> set a=a+2; -> end if; -> select a; -> end// Query OK, 0 rows affected (0.00 sec) mysql> call `if`(1)// +------+ | a | +------+ | 2 | +------+ 1 row in set (0.01 sec) Query OK, 0 rows affected (0.01 sec) mysql> call `if`(-2)// +------+ | a | +------+ | 0 | +------+ 1 row in set (0.01 sec) Query OK, 0 rows affected (0.01 sec)
case語句
case [變量名] when [值] then [執行內容] when [值] then [執行內容] ... else [執行內容] end case;
case語句實例:
mysql> create procedure `case`(in num int) -> begin -> case num -> when 0 then -> set num=num+1; -> when 1 then -> set num=num-2; -> else -> set num=num-3; -> end case; -> select num; -> end // Query OK, 0 rows affected (0.00 sec) mysql> call `case`(0)// +------+ | num | +------+ | 1 | +------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> call `case`(1)// +------+ | num | +------+ | -1 | +------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) mysql> call `case`(9)// +------+ | num | +------+ | 6 | +------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec)
4)循環語句
while語句,先判斷后運行
while [判斷語句] do [執行內容] end while;
while語句實例:
mysql> create procedure `while`(in num int) -> begin -> declare var int; -> set var=0; -> while var<num do -> set var=var+1; -> end while; -> select var; -> end // Query OK, 0 rows affected (0.00 sec) mysql> call `while`(5)// +------+ | var | +------+ | 6 | +------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec)
repeat語句,先運行后判斷
repeat [執行內容] until [判斷語句] end repeat;
repeat語句實例:
mysql> create procedure `repeat`(in num int) -> begin -> declare var int; -> set var=0; -> repeat -> set var=var+2; -> until var>num -> end repeat; -> select var; -> end // Query OK, 0 rows affected (0.00 sec) mysql> call `repeat`(5)// +------+ | var | +------+ | 6 | +------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec)
loop語句,運行直到遇到leave
[標簽名]:loop [執行內容] leave [標簽名] [執行內容] end loop;
loop語句實例:
mysql> create procedure `loop`(in num int) -> begin -> declare var int; -> set var=0; -> label1:loop -> set var=var+2; -> if var>num then -> leave label1; -> end if; -> end loop; -> select var; -> end // Query OK, 0 rows affected (0.00 sec) mysql> call `loop`(5)// +------+ | var | +------+ | 6 | +------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec)