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

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

文章目录

  • 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 开发能力。


相关文章:

  • shell编程基础(第x篇:子进程知识点汇总)
  • MySQL日志详解
  • Spring事务开发经验 回滚和不回滚?
  • AI应用实战:Excel表的操作工具
  • 51la 统计登录日志-悟空统计成为高效的选择
  • (004)Excel 监视窗口
  • MIT6.S081-lab7
  • 清晰易懂的跨域请求知识——拿捏
  • 《解锁CSS Flex布局:重塑现代网页布局的底层逻辑》
  • 实习技能记录【4】-----消息分发中的观察者模型
  • Canvas基础篇:绘制矩形
  • Git 实操:如何使用交互式 Rebase 移除指定提交(真实案例分享)
  • gradle 下载的tencent的镜像
  • Spark,集群搭建-Standalone
  • 企业战略管理(设计与工程师类)-2-战略规划及管理过程-2-外部环境分析-PESTEL模型实践
  • 从“丈量勘界”到“云端智管”:解码自然资源统一调查监测的智慧密码
  • Linux 下编译BusyBox
  • 《算法笔记》10.5小节——图算法专题->最小生成树 问题 B: Freckles
  • TTL、RS-232 和 RS-485 串行通信电平标准区别解析
  • 如何对多维样本进行KS检验
  • 李在明涉嫌违反《公职选举法》案将于5月1日宣判
  • 今年一季度全国城镇新增就业308万人,就业形势保持总体稳定
  • 王毅会见泰国外长玛里:坚决有力打击电诈等跨境犯罪
  • 丁俊晖连续7年止步世锦赛16强,中国军团到了接棒的时候
  • 释新闻|西葡大停电为何规模大、恢复慢?可再生能源是罪魁祸首?
  • “杭州六小龙”的招聘迷局