当前位置: 首页 > web >正文

存储过程补充——定义条件、处理程序及游标使用

文章目录

  • 1. 定义条件与处理程序
    • 1.1 定义条件
    • 1.2 处理程序
    • 1.3 案例演示
  • 2. 游标
    • 2.1 使用游标
      • 第一步,声明游标
      • 第二步,打开游标
      • 第三步,使用游标(从游标中取得数据)
      • 第四步,关闭游标
    • 2.2 举例
    • 2.3 小结


在 MySQL 数据库的开发过程中,为了提升程序的健壮性、可靠性以及数据处理的灵活性,常常需要面对错误处理和结果集逐行操作的问题。定义条件与处理程序、游标就是 MySQL 提供的强大工具,它们分别用于更精细地控制和处理错误异常情况,以及对查询结果集中的每一行数据进行访问和操作。本文将深入介绍这些重要特性,通过详细的语法说明和丰富的案例演示,帮助大家更好地掌握和运用它们。


1. 定义条件与处理程序

在 MySQL 中,定义条件处理程序 主要用于存储过程、函数、触发器等复杂的程序单元里,帮助开发者对错误和异常情况进行更精细的控制和处理,从而提升程序的健壮性和可靠性。

  • 定义条件 是事先定义程序执行过程中可能遇到的问题;
  • 处理程序 定义了在遇到问题时应当采取的处理方式,保证存储过程或函数在遇到警告或错误时能继续执行。

1.1 定义条件

定义条件是一种命名异常的方式,将一个错误码或错误条件与一个自定义的名称关联起来,让代码更具可读性和可维护性。

当程序执行过程中出现错误时,使用自定义的名称来指代特定的错误,避免在代码里直接使用错误码,使代码更易理解和管理。

  • 定义条件使用DECLARE语句,语法格式如下:
DECLARE 错误名称 CONDITION FOR 错误码(或错误条件)
  • 错误码的说明:
  • MySQL_error_codesqlstate_value 都可以表示MySQL的错误。
    • MySQL_error_code数值类型 错误代码。
    • sqlstate_value 是长度为5的 字符串类型 错误代码。
  • 例如,在 ERROR 1418 (HY000) 中,1418是MySQL_error_code,'HY000’是sqlstate_value。
  • 例如,在 ERROR 1142 (42000) 中,1142是MySQL_error_code,'42000’是sqlstate_value。
  • 例如,定义“Field_Not_Be_NULL”错误名与MySQL中违反非空约束的错误类型是“ERROR 1048 (23000)”对应。
#使用MySQL_error_code
DECLARE Field_Not_Be_NULL CONDITION FOR 1048;#使用sqlstate_value
DECLARE Field_Not_Be_NULL CONDITION FOR SQLSTATE '23000';
  • 例如,定义"ERROR 1148(42000)"错误,名称为command_not_allowed
#使用MySQL_error_code
DECLARE command_not_allowed CONDITION FOR 1148;#使用sqlstate_value
DECLARE command_not_allowed CONDITION FOR SQLSTATE '42000';

1.2 处理程序

处理程序用于指定当特定错误或异常发生时要执行的操作。在程序运行过程中,一旦出现预定义的错误或异常,就会执行相应的处理程序,从而避免程序崩溃,同时可以根据具体情况进行错误日志记录、回滚事务等操作。

  • 定义处理程序时,使用 DECLARE语句 的语法如下:
DECLARE 处理方式 HANDLER FOR 错误类型 处理语句;

处理方式:处理方式有3个取值:CONTINUEEXITUNDO

  • CONTINUE :表示遇到错误不处理,继续执行。
  • EXIT :表示遇到错误马上退出。
  • UNDO :表示遇到错误后撤回之前的操作。MySQL中暂时不支持这样的操作。

错误类型(即条件)可以有如下取值:

  • SQLSTATE '字符串错误码' :表示长度为5的sqlstate_value类型的错误代码;
  • MySQL_error_code :匹配数值类型错误代码;
  • 错误名称 :表示DECLARE … CONDITION定义的错误条件名称。
  • SQLWARNING :匹配所有以01开头的SQLSTATE错误代码;
  • NOT FOUND :匹配所有以02开头的SQLSTATE错误代码;
  • SQLEXCEPTION :匹配所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE错误代码;

处理语句:如果出现上述条件之一,则采用对应的处理方式,并执行指定的处理语句。语句可以是 像“ SET 变量 = 值 ”这样的简单语句,也可以是使用 BEGIN … END 编写的复合语句。

  • 定义处理程序的几种方式,代码如下:
#方法1:捕获sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info = 'NO_SUCH_TABLE';#方法2:捕获mysql_error_value
DECLARE CONTINUE HANDLER FOR 1146 SET @info = 'NO_SUCH_TABLE';#方法3:先定义条件,再调用
DECLARE no_such_table CONDITION FOR 1146;
DECLARE CONTINUE HANDLER FOR NO_SUCH_TABLE SET @info = 'NO_SUCH_TABLE';#方法4:使用SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING SET @info = 'ERROR';#方法5:使用NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND SET @info = 'NO_SUCH_TABLE';#方法6:使用SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info = 'ERROR';

1.3 案例演示

在存储过程中,定义处理程序,捕获 sqlstate_value 值,当遇到 MySQL_error_code值 为1048 时,执行 CONTINUE 操作,并且将 @proc_value 的值设置为-1。

DELIMITER //CREATE PROCEDURE UpdateDataNoCondition()BEGIN#定义处理程序DECLARE CONTINUE HANDLER FOR 1048 SET @proc_value = -1;SET @x = 1;UPDATE employees SET email = NULL WHERE last_name = 'Abel';SET @x = 2;UPDATE employees SET email = 'aabbel' WHERE last_name = 'Abel';SET @x = 3;END //
DELIMITER ;

调用过程:

mysql> CALL UpdateDataWithCondition();
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT @x,@proc_value;
+------+-------------+
|   @x | @proc_value |
+------+-------------+
|    3 |          -1 |
+------+-------------+
1 row in set (0.00 sec)

在存储过程中,定义处理程序,当执行 SELECT * FROM non_existent_table; 语句时,如果表不存在(错误码 1146),就会触发处理程序,记录错误日志,然后继续执行后续语句。

-- 创建错误日志表
CREATE TABLE error_log (id INT AUTO_INCREMENT PRIMARY KEY,error_message VARCHAR(255),error_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);DELIMITER //CREATE PROCEDURE test_procedure()
BEGIN-- 定义条件DECLARE table_not_found CONDITION FOR 1146;-- 定义处理程序DECLARE CONTINUE HANDLER FOR table_not_foundBEGIN-- 记录错误日志INSERT INTO error_log (error_message) VALUES ('Table not found');-- 可以在这里添加其他处理逻辑END;-- 尝试查询一个可能不存在的表SELECT * FROM non_existent_table;-- 继续执行后续语句SELECT 'Procedure continues...';
END //DELIMITER ;    

2. 游标

游标是指向查询结果集中某一行的指针,通过游标可以在结果集中进行移动,从而对每一行数据进行访问和处理。在 SQL 语句中,查询操作通常会返回一个结果集,而游标提供了一种机制,允许按顺序逐个处理结果集中的行,这在需要对每一行数据进行复杂操作时非常有用。

在这里插入图片描述

2.1 使用游标

游标必须在声明处理程序之前被声明,并且变量和条件还必须在声明游标或处理程序之前被声明。

第一步,声明游标

在MySQL中,使用 DECLARE 关键字来声明游标,其语法的基本形式如下:

DECLARE cursor_name CURSOR FOR select_statement;

这个语法适用于 MySQL,SQL Server,DB2 和 MariaDB。如果是用 Oracle 或者 PostgreSQL,需要写成:

DECLARE cursor_name CURSOR IS select_statement;

要使用 SELECT 语句来获取数据结果集,而此时还没有开始遍历数据,这里 select_statement 代表的是 SELECT 语句,返回一个用于创建游标的结果集。比如:

DECLARE cur_emp CURSOR FOR
SELECT employee_id,salary FROM employees;DECLARE cursor_fruit CURSOR FOR
SELECT f_name, f_price FROM fruits ;

第二步,打开游标

打开游标的语法如下:

OPEN cursor_name;

当我们定义好游标之后,如果想要使用游标,必须先打开游标。打开游标的时候 SELECT 语句的查询结果集就会送到游标工作区,为后面游标的逐条读取结果集中的记录做准备。

OPEN cur_emp ;

第三步,使用游标(从游标中取得数据)

从游标中取得数据语法如下:

FETCH cursor_name INTO var_name [, var_name] ...

这句的作用是使用 cursor_name 这个游标来读取当前行,并且将数据保存到 var_name 这个变量中,游标指针指到下一行。如果游标读取的数据行有多个列名,则在 INTO 关键字后面赋值给多个变量名即可。

注意:var_name必须在声明游标之前就定义好。

FETCH cur_emp INTO emp_id, emp_sal ;

注意:游标的查询结果集中的字段数,必须跟 INTO 后面的变量数一致,否则,在存储过程执行的时候,MySQL 会提示错误。

第四步,关闭游标

关闭游标语法如下:

CLOSE cursor_name;

当使用完游标后需要关闭掉该游标。因为游标会占用系统资源 ,如果不及时关闭,游标会一直保持到存储过程结束,影响系统运行的效率。而关闭游标的操作,会释放游标占用的系统资源。

关闭游标之后,我们就不能再检索查询结果中的数据行,如果需要检索只能再次打开游标。

CLOSE cur_emp;

2.2 举例

创建存储过程“get_count_by_limit_total_salary()”,声明IN参数 limit_total_salary,DOUBLE类型;声明 OUT参数total_count,INT类型。函数的功能可以实现累加薪资最高的几个员工的薪资值,直到薪资总和 达到limit_total_salary参数的值,返回累加的人数给total_count。

DELIMITER //CREATE PROCEDURE get_count_by_limit_total_salary(IN limit_total_salary DOUBLE,OUT total_count INT)
BEGINDECLARE sum_salary DOUBLE DEFAULT 0; #记录累加的总工资DECLARE cursor_salary DOUBLE DEFAULT 0; #记录某一个工资值DECLARE emp_count INT DEFAULT 0; #记录循环个数#定义游标DECLARE emp_cursor CURSOR FOR SELECT salary FROM employees ORDER BY salary DESC;#打开游标OPEN emp_cursor;REPEAT#使用游标(从游标中获取数据)FETCH emp_cursor INTO cursor_salary;SET sum_salary = sum_salary + cursor_salary;SET emp_count = emp_count + 1;UNTIL sum_salary >= limit_total_salaryEND REPEAT;SET total_count = emp_count;#关闭游标CLOSE emp_cursor;
END //
DELIMITER ;

2.3 小结

游标为逐条读取结果集中的数据,提供了完美的解决方案。跟在应用层面实现相同的功能相比,游标可以在存储程序中使用,效率高,程序也更加简洁。

但同时也会带来一些性能问题,比如在使用游标的过程中,会对数据行进行加锁 ,这样在业务并发量大的时候,不仅会影响业务之间的效率,还会消耗系统资源 ,造成内存不足,这是因为游标是在内存中进行的处理。

建议养成用完之后就关闭的习惯,这样才能提高系统的整体效率。


总之,定义条件与处理程序、游标在 MySQL 开发中各有其独特价值。前者让错误处理更精细,增强程序健壮性;后者为结果集逐行处理提供高效简洁方案。但使用游标时要警惕性能问题,及时关闭以提升系统效率。希望大家能借此提升 MySQL 开发能力。


http://www.xdnf.cn/news/3062.html

相关文章:

  • PID速度、电流、位置闭环
  • swagger2升级至openapi3的利器--swagger2openapi
  • Linux 用户管理
  • 数据处理方式 之 对数变换 和Box-Cox变换以及对应逆变换【深度学习】
  • JavaScript基础
  • 使用C# ASP.NET创建一个可以由服务端推送信息至客户端的WEB应用(1)
  • Qwen3术语解密
  • 【SAM2代码解析】数据集处理2
  • go打印金字塔
  • 探索行业的新可能 - 你有遇到这些挑战吗?
  • 创新应用 | 食堂餐牌显示的“秒变”革新
  • Python深度挖掘:openpyxl和pandas的使用详细
  • 优雅的酸碱中和反应动画演示工具
  • 仿腾讯会议——注册登录UI
  • docker 使用
  • 数据采集脱硫脱硝除尘实验装置
  • DTO,VO,PO,Entity
  • 第一个机器人程序
  • C语言教程(二十):C 语言 typedef 关键字详解
  • AVL树左旋右旋的实现
  • C语言加餐--浮点数比较
  • 文件基础-----C语言经典题目(10)
  • 前端Vue3 + 后端Spring Boot,前端取消请求后端处理逻辑分析
  • 第35周Zookkeeper+Dubbo Zookkeeper
  • Transformer数学推导——Q32 可学习位置编码的梯度更新公式推导
  • Arkts完成数据请求http以及使用axios第三方库
  • 杭州数据库恢复公司之Dell服务器RAID5阵列两块硬盘损坏报警离线
  • 服务器远程超出最大连接数的解决方案是什么?
  • 如何创建并使用极狐GitLab 项目访问令牌?
  • 基于esp32的小区智能门禁集成系统设计和实现