一、什么是存储过程?
stroed procedure
存储过程是在数据库系统中, 一组为了完成特定功能的sql语句集, 静编译后存储在数据库中,
用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。
存储过程不仅仅是"批处理"
存储过程是经过编译的sql语句集
二、存储过程与函数和触发器的区别?
从语法上看, 存储过程和函数以及触发器是十分类似的。我们甚至可以说, 触发器和函数就是一种特别存储过程。
不过他们之间还是有一些区别的:
- 触发器用于完成一些触发条件所引发的操作。 触发器的执行是自动化的
- 自定义函数只能通过return语句返回单个值或者表对象, 而存储过程不能调用return语句, 但可以通过out参数返回多个值。函数可以在sql语句中结合使用。 函数不能用临时表, 只能用表变量,还有一些系统函数都不可用等等
- 存储过程用于完成一系列的sql操作, 批量化的完成数据库操作工作, 由使用者调用执行。
三、为什么使用存储过程?
- 存储过程只在创造时进行编译, 以后每次执行存错过程都不需要在重新编译, 而一般SQL
语句每执行一次就编译一次, 所以使用存储过程可提高数据库执行速度。 - 当丢数据库进行复杂操作时(如对多个表进行Update, Insert, Query, Delete),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。
这些操作, 如果用程序来完成, 就变成了一条条的sql语句, 可能要多次连接数据库。而换成存储, 就只需要连接一次数据库就可以了 - 存储过程可以重复使用, 可减少数据库开发人员的工作量。
- 安全性高, 可设定只有某此用户才具有对指定存储过程的使用权。
四、为什么不使用存储过程
- 可移植性差
- 对于很简单的sql语句, 存储过程没有优势
- 如果存储过程中不一定会减少网络传输(包含的sql数量并不多, 并且执行很快,就没必要了)
- 如果只有一个用户使用数据库, 那么存储过程对于安全也没什么影响
- 团队开发时需要先统一标准, 否则后期维护是个麻烦
- 在大并发量访问的情况下, 不宜写过多涉及运算的存储过程
- 业务逻辑复杂时, 特别是涉及到对很大的表进行操作的时候, 不如在前端先简化业务逻辑
五、查看存储过程状态
与查看函数和触发器一样, 可是使用show status语句查看存储过程状态
show procedure status like 'p%'\G;
select * from information_schema.Routines where routine_name='p1' and routine_type='PROCEDURE'\G;
六、查看存储过程内容
show create procedure p2\G;
七、例子
delimiter // 定界符, 用于修改结束符, 方便些多条sql语句, 最后在修改回来
create procedure 名称(out s int)
begin
select count(*) into s from mysql.user;
end
//
delimiter;
call 存储过程名称(@s) 执行;
select @s
八、存储过程参数
mysql存储过程的参数用于存储过程的定义, 共有三种参数类型, IN, OUT, INOUT,形式如下:
CREATE PROCEDURE (【in|out|inout】 函数名 函数类型...)
IN 输入参数: 表示该参数的值必须在调用存储过程时指定, 在存储过程中修改该参数的值不能被返回, 为默认值。
OUT 输出参数: 该值可在存储过程内部被改变, 并可返回。
INOUT输入输出参数: 调用时指定, 并且可被改变和返回。
IN参数例子:
IN参数的特定在于, 读取外部变量值, 且有效范围仅限于存储过程内部。
例子:
delimiter //
create procedure pin(IN p_in int)
begin
select p_in;
set p_in=2;
select p_in;
end;
//
delimiter;
-----------
set @p_in=1;
call pin(@p_in) 无论内部如何修改, 都不会被传递到外部
select @p_in 还是1, 而不是函数修改后的2
OUT参数例子
out参数的特点在于, 不读取外部变量值, 在存储过程执行完毕后保留新值。
delimiter //
create procedure pout(out p_out int)
begin
select p_out; 不接受参数, 值为null
set p_out = 2;
select p_out;
end;
//
delimiter ;
--------------
set @p_out=1; 这个@就是声明参数的意思
call pout(@p_out);
如果在查询
select @p_out; 结果是2
INOUT 参数例子
INOUT参数的特点在于, 读取外部变量值, 在存储过程执行完毕后保留新值
delimiter //
create procedure pinout(inout p_inout int)
begin
select p_inout;
set p_inout = 2;
select p_inout;
end;
//
delimiter ;
----------
set @p_inout = 1; 先设置值为1, 存储过程查看
call pinout(@p_inout);
select @p_inout;
不加参数例子
如果在创建存储过程时没有指定参数类型, 则需要调用的时候指定参数值。
delimiter //
create definer=`root`@`localhost` procedure `test1` (n1 int)
begin
set @x=0;
repeat set @x = @x+1; 循环
end repeat;
end;
delimiter;
--------
call test1(10);
变量定义
1. 局部变量:局部变量一般用在sql语句块中,比如存储过程的begin/end。
2. 用户变量:用户变量的作用域要比局部变量要广。用户变量可以作用于当前整个连接,但是当当前连接断开后,其所定义的用户变量都会消失。
3. 会话变量:服务器为每个连接的客户端维护一系列会话变量。
4. 全局变量:全局变量影响服务器整体操作。当服务器启动时,它将所有全局变量初始化为默认值
一、局部变量
局部变量一般用在sql语句块中,比如存储过程的begin/end。其作用域仅限于该语句块,在该语句块执行完毕后,局部变量就消失了。
局部变量一般用declare来声明,可以使用default来说明默认值。
drop procedure if exists add;
create procedure add
(
in a int,
in b int
)
begin
declare c int default 0;
set c = a + b;
select c as c;
end;
mysql 中使用declare 进行变量定义。语法:
delcare variable_name [, variable_name...] datatype [default value];
其中, datatype 为mysql的数据类型, 例如:
int float, date, varchar(length)
例如:
declare i_int int unsigned default 40000;
declare i_varchar varchar(255)defalt "This will not be padded";
也可以
declare var int;
set var = p1 + 1;
二、用户变量
用户变量的作用域要比局部变量要广。用户变量可以作用于当前整个连接,但是当当前连接断开后,其所定义的用户变量都会消失。
用户变量使用如下(这里我们无须使用declare关键字进行定义,可以直接这样使用):
select @变量名
对用户变量赋值有两种方式,一种是直接用"=“号,另一种是用”:=“号。其区别在于使用set命令对用户变量进行赋值时,两种方式都可以使用;当使用select语句对用户变量进行赋值时,只能使用”:=“方式,因为在select语句中,”="号被看作是比较操作符。
示例程序如下:
drop procedure if exists math;
create procedure math
(
in a int,
in b int
)
begin
set @var1 = 1;
set @var2 = 2;
select @sum:=(a + b) as sum, @dif:=(a - b) as dif;
end;
执行结果
mysql> call math(3, 4);
+------+------+
| sum | dif |
+------+------+
| 7 | -1 |
+------+------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
mysql> select @var1; //var1为用户变量
+-------+
| @var1 |
+-------+
| 1 |
+-------+
1 row in set (0.00 sec)
mysql> select @var2; //var2为用户变量
+-------+
| @var2 |
+-------+
| 2 |
+-------+
1 row in set (0.00 sec)
三、变量赋值
mysql 中使用set命令进行变量赋值。 语法:
SET 变量名 = 值
注意: 变量赋值是可以在不同存储过程中继承的。
例1:
create procedure p1() set @last_procedure = 'p1';
create procedure p2() concat('last procedure was ', @last_proc);
call p1();
call p2();
四、变量的作用域:
内部的变量是其作用域范围内享有更高的优先权, 当执行到end, 内部变量消失, 此时已经
在其作用域外, 变量不再可见了。因为在存储过程外也不能找到这个声明的变量, 但是你可以通过
out参数或者将其指派给会话变量来保存其值。
内部变量在begin – end 之间
注释:
-- 单行注释
/**/ 多行注释
if 语句
IF -- THEN -- ELSE
例子:
delimiter //
create procedure proc2(IN p1 int)
begin
declare var int;
set var=p1 + 1;
IF var = 1 THen insert into t values(11);
end if; /* if 结束*/
if var = 2 then insert into t values (22);
else insert into values (33);
end if;
end;
//
delimiter ;
case 语句
delimiter //
create procedure proc3(IN p1 int)
begin
declare var int;
set var = p1 + 1;
case var
when 1 then insert into t values(17);
when 2 then insert into t values(18);
else insert into t values(19);
end case;
end;
//
delimiter ;
WHILE语句
DELIMITER //
create procedure proc4()
begin
declare var int;
set var=0;
while var < 6 do
insert into t values(var);
set var = var + 1;
end while;
end;
//
delimiter;
repeat 语句
类似于for循环 又有点类似于c语言的go while, 个人认为
delimiter //
create procedure proce5()
begin
declare v int;
set v=0;
repeat
insert into t values(v);
set v = v+1;
until v < 5
end repeat;
end;
//
delimiter;