一、存储过程
1.1 存储过程介绍
存储过程:
将能够完成特定功能的sql指令进行封装(sql指令集),编译之后存储在数据库服务器上,并为其命名,客户端可以通过直接调用sql指令集,获取执行结果
存储过程解决的问题:
- 如果有需要多次执行的sql,每次执行都需要通过连接传递到mysql服务器,并且需要经过编译和执行后,再返回执行结果。重复且浪费资源
- 如果需要连续执行多个sql指令,并且第二个sql指令需要使用第一个sql执行的结果集作为参数。
存储过程优点:
- sql指令无需客户端编写、通过网络传输,可以节省网络开销,同时避免sql指令在传输过程中被恶意篡改,保证安全性;
- 存储过程经过编译创建并保存在数据库服务器中,执行过程无需编译,对sql指令的执行过程提升了性能;
- 存储过程中多个sql指令之间存在逻辑关系,支持流程控制语句(分支、循环),可以实现更为复杂的业务逻辑处理;
存储过程的缺点:
- 存储过程是根据不同数据库引擎进行编译、创建并存储在数据库中。如果需要不同类型数据库迁移,需要对数据库存储过程进行重新编写。
- 存储过程受限与数据库产品,如果需要高性能的优化会成为一个问题;
- 在互联网项目中,如果需要数据库高并发(连接)访问,存储过程会增加数据库的连接执行时间。因为我们将复杂的业务交给了数据库进行处理。
1.2 存储过程的创建与删除
1.2.1 创建存储过程
将能够完成特定功能的sql指令进行封装
语法
create procedure <proc_name>([in/out args]) begin -- sql end;
示例
-- 创建存储过程,实现加法运算 -- 存储过程是有出入参数和输出参数的 create procedure proc_test1(in a int,in b int,out c int) begin set c = a+b; end;
1.2.2 删除存储过程
-- 删除存储过程 drop procedure proc_test1;
1.3存储过程的调用
-- 定义变量 set @m = 0; -- 调用存储过程 call proc_test1(3,2,@m); -- 显示变量值 select @m from dual;
1.4 存储过程中的变量使用
存储过程中的变量分为两种:局部变量和用户变量
1.4.1 局部变量
局部变量:定义在存储过程中的变量,只能在存储过程内部使用
-- 局部变量需要定义在存储过程中,而且必须定义在存储过程开始 declare <attr_name> <type> [default value]; -- 创建存储过程:计算输入参数的平方与输入参数/2 之和 create procedure proc_test2(in a int,out r int) begin declare x int default 0; -- 局部变量定义 declare y int default 0; -- 局部变量定义 set x = a*a; set y = a/2; set r = x + y ; end
1.4.2 用户变量
用户变量:相当于全局变量,定义的用户变量,可以通过
select @attrname from dual
进行查询;
-- 用户变量会存储在mysql数据库的数据字典中(dual) -- 用户变量定义使用set关键字直接定义,变量名要以@开头 set @a = 0; -- 定义用户变量 select @a from dual;-- 查询用户变量
1.4.3 将查询结果赋值给变量
在存储过程中,使用
select ... into
给变量赋值
-- 创建存储过程,查询学生表中的学生数量,赋值给参数s create procedure proc_test3(out s int) begin select count(stu_num) into s from students;-- 将查询到的学生数量,赋值给参数s end; -- 调用存储过程test3 set @s=0; call proc_test3(@s); select @s from dual;
注意
用户变量相当于全局变量,可以在sql质量以及多个存储过程中共享,因此在开发中建议尽量减少使用用户变量,防止用户变量过多导致程序不易理解、难以维护;
1.5存储过程的参数
mysql存储过程的参数一共有三种:in 、out、inout
1.5.1 输入参数 in
输入参数–在调用存储过程中传递给存储过程的参数(在调用的过程必须为具有实际变量的 或者 字面值)
-- 创建存储过程:添加学生信息 create procedure proc_test4 (in snum char(8),in sname varchar(20),in denger char(2),in age int,in tel varchar(20),in cid int) begin insert into students(stu_num,stu_name,stu_denger,stu_age,stu_tel,cid) values(snum,sname,denger,age,tel,cid); end; -- 调用存储过程 call proc_test4('8','张飞','男',88,'13667565656',2);
1.5.2 输出参数 out
将存储过程中产生的数据,返回给过程调用者,相当于java的返回值,但不同的是,存储过程可以有多个输出参数。
-- 创建存储过程:根据学号,查询学生姓名 create procedure proc_test5(in snum int,out sname varchar(20)) begin select stu_name into sname from students where stu_num = snum; end; -- 设置用户参数 set @name = ''; -- 调用存储过程 call proc_test5(8,@name); select @name from dual;
1.5.3 输入输出参数 inout
-- 存储过程:根据学号,查询学生姓名,使用inout create procedure proc_test6(inout str varchar(20)) begin select stu_name into str from students where stu_num = str; end; -- 设置参数,默认赋值为查询参数值 set @str = '8'; -- 调用存储过程 call proc_test6(@str); select @str from dual;
1.6 存储过程中的流程控制
在存储过程中,支持流程控制语句用于实现逻辑的控制
1.6.1 分支语句
if-then-else
单分支:
– 单分支:如果条件成立,则执行sql
create procedure test7(in a int)
begin
if condition then
– sql
end if;
end;
双分支
– 双分支:如果条件成立,则执行sql1;否则,执行sql2
create procedure test7(in a int)
begin
if condition then
– sql1
else
– sql2
end if;
end;
case
– case
create procedure proc_test8(in a int)
begin
case a
when 1 then – 参数a = 1 时,执行sql1
– sql1
when 2 then – 参数a = 2 时,执行sql2
– sql2
else
– sql3 – 如果变量值和所有的when值都不匹配,则执行sql3
end case;
end;
1.6.2 循环语句
while
– 创建存储过程:添加参数,按照参数值,创建班级信息,即参与为3,就创建3条班级信息
create procedure proc_test7(in num int)
begin
declare i int; – 局部变量
set i = 0;
while i<num do – i < 参数变量时,循环执行sql语句
– sql
set i = i+1; – 每循环一次,i增加1
end while;
end;
repeat
– repeat 创建存储过程:添加参数,按照参数值,创建班级信息,即参与为3,就创建3条班级信息
create procedure proc_test7(in num int)
begin
declare i int; – 局部变量
set i = 0;
repeat – 循环执行sql
– sql
set i = i+1; – 每执行一次,i+1
until i > num; – until 判断后面结果,符合即跳出循环
end while;
end;
loop
– loop 创建存储过程:添加参数,按照参数值,创建班级信息,即参与为3,就创建3条班级信息
create procedure proc_test7(in num int)
begin
declare i int; – 局部变量
set i = 0;
myloop:loop – 设置myloop,在myloop中循环执行sql
– sql
set i = i+1; – 每循环一次,i+1
if i = num then – 判断当i = 参数值时
leave myloop; – 跳出myloop循环
end if;
end loop;
end;
1.7 存储过程管理
1.7.1 查询存储过程
存储过程隶属于某个数据库的,也就是说,当我们将存储过程创建在某个数据库中,只能在当前数据库中调用,不能跨库调用
-- 根据数据库名,查询当前数据库中的存储过程 show procedure status where db = 'db_test'; -- 查询存储过程的创建细节 show create procedure db_test.proc_test1;
1.7.2 修改存储过程
修改存储过程,主要是指修改存储过程的特征/特性
alter procedure <proc_name> 特征1 {特征2...}
存储过程的特征参数
contains sql
表示子程序包含sql语句,但不包含读或写的数据操作no sql
表示子程序不包含sql语句reads sql data
表示子程序包含读数据的语句modifies sql data
表示子程序中包含写数据的语句sql security {definer| invoker}
指明谁有权限来执行definer
定义者才有执行权限invoker
调用者可以执行comment string
表示注释信息
– 修改存储过程
alter procedure proc_test1 no sql;
1.7.3 删除存储过程
删除存储过程
-- 删除存储过程 drop drop procedure proc_test1;
二、存储过程案例
使用存储过程,完成借书操作
2.1 准备数据
数据库准备:新建数据库
## 创建数据库 create database da_test3; ## 使用数据库 use db_test3;
数据表及数据准备
-- 创建图书信息表 create table books( book_id int primary key auto_increment, book_name varchar(50) not null, book_author varchar(20) not null, book_price decimal(10,2) not null, book_stock int not null, book_desc varchar(200) ); -- 添加图书信息 insert into books(book_name,book_author,book_price,book_stock,book_desc) values ('java从入门到放弃','斯蒂芬',28.80,100,'一本带你从入门到放弃的java顶级教材'); insert into books(book_name,book_author,book_price,book_stock,book_desc) values ('mysql从入门到放弃','库里',68.20,20,'一本带你从入门到放弃的mysql顶级教材'); -- 创建学生信息表 create table students( stu_num char(8) primary key, stu_name varchar(20) not null, stu_denger char(2) not null, stu_age int not null ); -- 添加学生信息 insert into students (stu_num,stu_name,stu_denger,stu_age) values('1001','不知火舞','女','20'); insert into students (stu_num,stu_name,stu_denger,stu_age) values('1002','安其拉','女','25'); insert into students (stu_num,stu_name,stu_denger,stu_age) values('1003','奕星','男','30');
2.2 创建存储过程
创建一个存储过程,实现借书的操作:哪个学生接了哪本数,借书数量
操作:
- 保存借书记录
- 修改图书库存
条件:
- 判断学生是否存在
- 判断图书是否存在,库存是否充足
创建借书记录表
-- 借书记录表 create table records( rid int primary key auto_increment, snum char(4) not null, bid int not null, borrow_num int not null, is_return int not null, -- 0-未归还;1-已归还 borrow_date date not null, constraint fk_records_students foreign key(snum) references students(stu_num), constraint fk_records_books foreign key(bid) references books(book_id) );
2.2.1 创建存储过程
-- 实现借书业务 -- 参数1: 输入参数 学号 a -- 参数2: 输入参数 图书标号 b -- 参数3: 输入参数 借书数量 m -- 参数4: 输出参数 借书状态(1-借书成功;2-学号不存在;3-图书不存在;4-库存不足) create procedure proc_borrow_book(in a char(4),in b int,in m int,out state int) begin declare stu_count int default 0; declare b_count int default 0; declare b_stock int default 0; -- 一、判断学号是否存在 根据参数a去学生表查询是否存在学生 select count(stu_num) into stu_count from students where stu_num = a; if stu_count > 0 then -- 学号存在 -- 二、查看图书编号是否存在 select count(book_id) into b_count from books where book_id = b; if b_count > 0 then -- 图书存在 -- 三、查询图书库存是否充足 select book_stock into b_stock from books where book_id = b; if b_stock >= m then -- 库存满足 -- 1、插入借书记录表 insert into records(snum,bid,borrow_num,is_return,borrow_date) values(a,b,m,0,sysdate()); -- 2、更新books表库存数据book_stock update books set book_stock = (b_stock - m) where book_id = b; -- 3、借书成功,返回成功状态 0 set state = 1; else -- 库存不足 set state = 4; end if; else -- 图书不存在 set state = 3; end if; else -- 学号不存在 set state = 2; end if; end;
2.2.2 测试
select * from students;-- 学生表 select * from books;-- 图书表 select * from records;-- 借书记录表 -- 测试借书存储过程 -- 1、正常借书成功业务测试:学生学号a = 1001;借书编号b = 1;借书数量m = 10; set @state = 0; call proc_borrow_book('1001',1,10,@state); select @state from dual; -- 2、测试学号不存在:学生学号a = 1008;借书编号b = 1;借书数量m = 10; set @state = 0; call proc_borrow_book('1008',1,10,@state); select @state from dual; -- 3、测试图书编号不存在:学生学号a = 1002;借书编号b = 8;借书数量m = 10; set @state = 0; call proc_borrow_book('1002',8,10,@state); select @state from dual; -- 4、测试图书库存不足:学生学号a = 1002;借书编号b = 2;借书数量m = 100; set @state = 0; call proc_borrow_book('1002',2,100,@state); select @state from dual;
到此这篇关于mysql存储过程的创建和使用的文章就介绍到这了,更多相关mysql存储过程使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论