存储过程是在大型数据库系统中一组为了完成特定功能的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)