什么是存储过程?
存储过程和函数都类似于Java中的方法。存储过程是一组预先编译好的sql指令集合。
预先编译好的,也就意味着,调用存储过程时,不再需要花时间去编译sql语句,直接就可以执行,从而提高效率。
好处:
- 提高代码重用性
- 简化操作
- 提高了效率
存储过程能解决什么问题?
使用存储过程
创建存储过程
语法:
create procedure 存储过程名(参数列表)
begin
存储过程体(一组sql语句)
end
注意点:
- 参数列表包含三部分:参数模式 参数名 参数类型。例如,
in stuname varchar(20)
- 参数模式:
IN
:表示该参数是输入参数,调用存储过程时,被in
修饰的参数必须传入值。OUT
:表示该参数可作为输出,即该参数是返回值INOUT
:表示该参数即可作为输入参数,又可作为输出(即返回值)。
- 若存储过程体中只有一句 sql 语句,
BEGIN END
可省略。 - 存储过程体中的每条sql语句必须以分号结尾。存储过程的结尾可以通过
delimiter
进行设置。
语法:
DELIMITER 结束符号
-- 如,下面的语句表示以$作为存储过程的结束符
DELIMITER $
调用存储过程
call 存储过程名(实参列表);
删除存储过程
drop procedure 存储过名1, 存储过名2,...;
查看存储过程的结构
show create procedure myp2;
存储过程使用实例
空参存储过程
select * from account;
-- 将结束符设为$
delimiter $
-- 创建存储过程
create procedure myp1()
begin
insert into account (username, balance)
values ('john', 1000), ('mark', 2000), ('mary', 3000), ('steve', 4000);
end $
--将结束符还原
delimiter ;
-- 调用存储过程
call myp1();
初始表:
+----+----------+---------+
| id | username | balance |
+----+----------+---------+
| 1 | 张无忌 | 500 |
| 2 | 赵敏 | 1000 |
+----+----------+---------+
执行存储过程后:
+----+----------+---------+
| id | username | balance |
+----+----------+---------+
| 1 | 张无忌 | 500 |
| 2 | 赵敏 | 1000 |
| 7 | john | 1000 |
| 8 | mark | 2000 |
| 9 | mary | 3000 |
| 10 | steve | 4000 |
+----+----------+---------+
带 IN 模式的存储过程
先举个简单的实例:
select * from account;
delimiter $
-- 参数列表中的username其实是个局部变量,就跟Java中一样
create procedure myp2(in username varchar(20))
begin
select * from account where account.username=username;
end $
delimiter ;
call myp2('张无忌');
结果:
MariaDB [myemployees]> call myp2('张无忌');
+----+----------+---------+
| id | username | balance |
+----+----------+---------+
| 1 | 张无忌 | 500 |
+----+----------+---------+
1 row in set (0.004 sec)
再举个复杂的例子(结合了变量概念):例如要用存储过程来实现用户登录成功与否
新建 admin 表:
create table admin (
id int primary key auto_increment,
username varchar(20) not null,
password varchar(20) not null
);
insert into admin (username, password) values ('admin', '123'), ('hello', '123456');
MariaDB [myemployees]> select * from admin;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 123 |
| 2 | hello | 123456 |
+----+----------+----------+
2 rows in set (0.000 sec)
创建存储过程:
select * from admin;
delimiter $
create procedure myp3(in username varchar(20), in password varchar(20))
begin
declare result int default 0;
select count(*) into result
from admin
where admin.username=username and admin.password=password;
select if(result>0, '登录成功', '登录失败');
end $
delimiter ;
call myp3('admin', '123');
思路:查询 admin 表中是否有指定 username 和 password 的记录,若记录数大于 0(这一点通过变量来实现),则意味着登录成功,否则失败。
结果:
MariaDB [myemployees]> call myp3('admin', '123');
+--------------------------------------+
| if(result>0, '登录成功', '登录失败') |
+--------------------------------------+
| 登录成功 |
+--------------------------------------+
1 row in set (0.003 sec)
带 OUT 模式的存储过程
例 1 :只使用一个 OUT 修饰的参数:查询 account 表中,指定 username 对应的 balance
select * from account;
delimiter $
create procedure myp4(in username varchar(20), out balance varchar(20))
begin
select a.balance into balance
from account a
where a.username=username;
end $
delimiter ;
call myp4('张无忌', @balance);
-- 读取out修饰的参数
select @balance;
结果:
MariaDB [myemployees]> select @balance;
+----------+
| @balance |
+----------+
| 500 |
+----------+
1 row in set (0.000 sec)
例 2 :使用两个 OUT 修饰的参数:查询 account 表中,指定 username 对应的 balance,以及 balance-1000 后的结果
select * from account;
delimiter $
create procedure myp5(in username varchar(20), out balance varchar(20), out balance_minus varchar(20))
begin
select a.balance, (a.balance-1000) into balance, balance_minus
from account a
where a.username=username;
end $
delimiter ;
call myp5('张无忌', @balance, @balance_minus);
-- 读取out修饰的参数
select @balance, @balance_minus;
结果:
MariaDB [myemployees]> select @balance, @balance_minus;
+----------+----------------+
| @balance | @balance_minus |
+----------+----------------+
| 500 | -500 |
+----------+----------------+
1 row in set (0.000 sec)
带 INOUT 模式的存储过程
例子:传入 a 和 b 两个值,返回二者翻倍后的结果
delimiter $
create procedure myp6(inout a int, inout b int)
begin
set a=a*2;
set b=b*2;
end $
delimiter ;
set @a:=2, @b:=5;
call myp6(@a, @b);
select @a, @b;
结果:
MariaDB [myemployees]> select @a, @b;
+------+------+
| @a | @b |
+------+------+
| 2 | 5 |
+------+------+
1 row in set (0.000 sec)
MariaDB [myemployees]> call myp6(@a, @b);
Query OK, 0 rows affected (0.000 sec)
MariaDB [myemployees]> select @a, @b;
+------+------+
| @a | @b |
+------+------+
| 4 | 10 |
+------+------+
1 row in set (0.000 sec)