五、存储过程
5.1 认识存储过程
5.1.1 存储过程简介
- 存储过程 是一组为了完成特定功能的 SQL 语句集合
- 经编译后保存在数据库中
- 通过指定存储过程的名字并给出参数的值
- 可带参数,也可返回结果
- 可包含数据操纵语句、变量、逻辑控制语句等
5.1.2 MySQL 存储过程的优缺点
存储过程的优点
- 减少网络流量 存储过程一般存储在数据库服务器上,应用程序不需要发送多个 SQL 语句,而只需要发送存储过程的名称和参数
- 提升执行速度 在 MySQL 中,对于存储过程只在创建时进行编译,然后将编译好的存储过程放在缓存中。若多次重复调用存储过程,则使用缓存中的编译版本
- 减少数据库连接次数 执行多条 SQL 语句,应用程序需要多次连接数据库,使用存储过程,应用程序只需要连接一次数据库
- 安全性高 数据库管理员可以对访问数据库存储过程的应用授予权限,而不提供基础数据表的访问权限
- 高复用性 存储过程是封装的一个特定的功能块,对于任何应用程序都是可复用的透明的
存储过程的缺点
- 内存增加 如果使用许多存储过程,则使用这些存储过程的每个连接的内存使用量将显着增加
- 开发和维护存储过程并不容易
- 调试存储过程很困难
5.2 使用存储过程
5.2.1 创建和调用存储过程
创建存储过程
- 使用 CREATE PROCEDURE 语句创建存储过程
- 创建存储过程 语法
CREATE PROCEDURE 过程名([过程参数[,...]])
[特性] #可选项,用于设置存储过程的行为
存储过程体
- 存储过程的常用特性
特性 | 说明 |
LANGUAGE SQL | 存储过程语音,默认为 SQL |
CONTAINS SQL NO SQL READS SQL DATA MODIFIES SQL DATA | 存储过程要做哪类工作 默认为CONTAINS SQL |
SQL SECURITY{DEFINER | INVOKER} | 用来指定存储过程的执行权限 默认值为 DEFINER DEFINER 使用创建者的权限执行 INVOKER 使用执行者的权限执行 |
COMMENT ‘string’ | 存储过程的注释信息 |
示例 编写存储过程,输出病人总人数
DROP PROCEDURE IF EXISTS proc_patient_countPatient;
DELIMITER // #声明分隔符
CREATE PROCEDURE proc_patient_countPatient()
BEGIN #过程体开始
SELECT COUNT(*) FROM patient;
END // #过程体结束
DELIMITER ; #恢复默认分隔符
1、删除存储过程
- 在创建存储过程之前,应先判断存储过程是否存在,如果存在,则删除
- 删除存储过程 语法
DROP PROCEDURE 过程名
2、声明语句分隔符
- MySQL 中,默认使用 ; 作为分隔符,使用 DELIMITER 关键字可以改变分隔符
- 创建过程前,首先声明分隔符
- 将分隔符设置为 $$ 或 // 语法如下
DELIMITER $$
DELIMITER //
- 如果没有声明分隔符,编译器就会把存储过程当成 SQL 语句处理,会出现报错
- 存储过程最后,要把分隔符还原 语法如下
DELIMITER ;
3、定义存储过程的参数
- MySQL 中,存储过程的参数包括 3 种类型
- IN 输入参数。该参数的值必须在调用存储过程时指定,在存储过程中可以使用该参数,但他不能被返回
- OUT 输出参数。该参数可以再存储过程中发生改变并可以返回
- INOUT 输入输出参数.该参数的值在调用存储过程时指定,在存储过程中可以被改变和返回。
- 定义参数 语法
[IN|OUT|INOUT] 参数名 类型
- 示例
DELIMITER // #声明分隔符
CREATE PROCEDURE proc_patient_countPatient2(IN patientNum INT)
#省略......
DELIMITER ; #恢复默认分隔符
4、过程体的标识
- 在定义存储过程的过程体时,需要标识开始和结束。
- 定义过程体 语法
BEGIN ...... END 分隔符
- END 后面必须使用 DELIMITER 语句中设置的分隔符为结束
调用存储过程
- MySQL 中使用 CALL 关键字调用存储过程
- 调用存储过程 语法
CALL 存储过程名 (参数列表);
创建和调用存储过程 示例
- 编写存储过程,输出病人总人数
#如果存储过程存在,则删除
DROP PROCEDURE IF EXISTS proc_patient_countPatient;
DELIMITER // #声明分隔符
CREATE PROCEDURE proc_patient_countPatient()
BEGIN #过程体开始
SELECT COUNT(*) FROM patient;
END // #过程体结束
DELIMITER ; #恢复默认分隔符
#调用
CALL roc_patient_countPatient();
5.2.2 存储过程中的变量
- 类似 Java 与其他编程语言,定义存储过程时可以使用变量
- 声明变量 语法
DECLARE 变量名[,变量名...] 数据类型 [DEFAULT 值];
- 示例 声明交易时间变量 trade_time,并设置默认值为 2020-07-10 代码如下
DECLARE trade_time DATE DEFAULT '2020-07-10';
- 所有局部变量的声明一定要放在存储过程体的开始,否则会提示语法错误
- 声明变量后,可以给变量赋值
- 变量赋值 语法
SET 变量名=表达式值[,变量名=表达式...];
- 示例 设置变量 total 的值为100
set total=100;
5.2.3 MySQL 用户自定义变量
- MySQL 中变量包括 用户自定义变量 和 系统变量两种
- MySQL 用户自定义变量又包括 局部变量 和 会话变量
- 局部变量
- 一般用于 SQL 的语句块中,如存储过程中的 BEGIN 和 END 语句块中
- 作用于仅限于定义该变量的语句块内,语句块结束,变量释放
- 会话变量
- 也成为用户变量
- 服务器为每个客户端连接维护的变量,与MySQL客户端是绑定的
- 可以暂存值,并传递给同一连接中其他SQL语句进行使用
- 当默认DEFINER = CURRENT_USERMySQL客户端连接退出时,用户变量就会被释放
- 用户变量创建时,一般以“@”开头,形式为“@变量名”
5.2.4 设置用户权限
- 存储过程中,可用关键字 DEFINER 赋值语句规定对存储过程访问的安全控制
- 使用 DEFINER 和 SQL SECURITY 特性控制存储过程的执行 语法
DELIMITER //
CREATE [DEFINER={user|CURRENT_USER}]
PROCEDURE 存储过程名
[SQL SECURITY {DEFINER|INVOKER|....}]
BEGIN
....
END //
DELIMITER ;
- DEFINER 指定创建者用户
- SQL SECURITY 用以指定 定义者 (DFINER) 或 调用者 (INVOKER)
5.2.5 查看存储过程
对创建后的存储过程进行查看
1、查看存储过程的状态
- 查看以创建的存储过程 语法
SHOW PROCEDURE STATUS
- 查看指定的数据库中创建的存储过程 语法
SHOW PROCEDURE STATUS WHERE DB='数据库名'
- 也可以通过 LIKE 关键字匹配存储过程名称 语法如下
SHOW PROCEDURE STATUS LIKE '%patient%';
2、查看存储过程的创建代码
- 查看存储过程的代码 语法
SHOW CREATE PROCEDURE 存储过程名
5.2.6 修改存储过程
- 对已创建的存储过程进行修改
- 只能修改存储过程定义的特性 语法如下
ALTER PROCEDURE 存储过程名 [特性......];
- ALTER 关键字只能修改存储过程的属性
- 如果要修改存储过程中过程体的内容,需要先删除该存储过程,然后进行重新创建
5.2.7 删除存储过程
- 删除已有的存储过程 语法
DROP PROCEDURE 存储过程名
5.3 存储过程的控制语句
MySQL 提供的控制语句包括条件语句、循环语句、迭代语句
5.3.1 条件语句
MySQL 提供了两种控制语句,分别是 IF-ELSEIF-ELSE 条件语句和 CASE 条件语句
1、IF-ELSEIF-ELSE 条件语句
- IF-ELSEIF-ELSE 语法
IF 条件 THEN 语句列表
[ELSEIF 条件 THEN 语句列表]
[ELSE 语句列表]
END IF;
- 如果 IF 后的条件为真,则执行 THEN 后的语句列表
2、CASE 条件语句
- MySQL 中的CASE 条件语句有两种写法
- 第一种 语法
CASE
WHEN 条件 THEN 语句列表
[WHEN 条件 THEN 语句列表]
[ELSE 语句列表]
END CASE;
- 第二种 语法
CASE 列名
WHEN 条件 THEN 语句列表
[WHEN 条件 THEN 语句列表]
[ELSE 语句列表]
END CASE;
- 在 CASE 语句中,如果条件为真,则相应的 SQL 语句列表会被执行
- 如果没有匹配条件,则会在 ELSE 子句里的语句列表被执行
- CASE 语句的两种写法可以实现相同的功能
- 如果做等值判断,使用第二种写法更加简洁
- 因为 CASE 后面有列名,功能上会有一些限制
5.3.2 循环语句
MySQL 语句提供多种循环语句,包括 WHILE 循环语句、LOOP 循环语句 和 REPEAT 循环语句
1、WHILE 循环语句
- WHILE 循环是最普遍使用的循环语句
- WHILE 循环 语法
[lable:] WHILE 条件 DO
语句列表
END WHILE [lable]
- 首先判断条件是否成立,若成立,则执行循环体
- label 及标号,用于区分不同的循环体,可以被省略
2、LOOP 循环
- LOOP 循环 语法
[lable:] LOOP
语句列表
END LOOP [lable];
- LOOP 循环结构不需要判断初始条件,直接执行循环体
- 直到遇到 LEAVE 语句才退出循环
- LEAVE 语法
LEAVE lable;
3、REPEAT 循环语句
- REPEAT 循环 语法
[lable:] REPEAT
语句列表
UNTLL 条件
END REPEAT [label]
- REPEAT 循环不需要初始条件就可以直接进入循环体
- REPEAT 循环有退出条件
- 每次循环一次后,判断 UNTLL 后的条件是否成立,如果成立,则跳出循环
5.3.3 迭代语句
- ITERATE 关键字可以嵌入 LOOP、WHILE、REPEAT 程序块中
- 执行 ITERATE 语句时,跳出本次循环,继续下一次循环
- ITERATE 语法
ITERATE lable;
- label 参数表示循环的标志,ITERATE 语句必须跟在循环标志前面