马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
一、存储过程
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 循环语句
- -- 创建存储过程:添加参数,按照参数值,创建班级信息,即参与为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 创建存储过程:添加参数,按照参数值,创建班级信息,即参与为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 创建存储过程:添加参数,按照参数值,创建班级信息,即参与为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;
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |