尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

MySQL进阶|游标与条件处理程序:存储过程逐行捕获异常

发布时间:2026/9/26 4:08:35

资讯中心
01
ARTICLE

MySQL进阶|游标与条件处理程序:存储过程逐行捕获异常

MySQL进阶|游标与条件处理程序:存储过程逐行捕获异常
博客主页小谢同学的小破站✍️本文由小谢同学的小破站原创首发于 CSDN ☕JavaSE专栏JavaSEJavaEE初阶专栏JavaEE初阶JavaEE进阶专栏JavaEE进阶数据结构专栏数据结构⚙️算法专栏算法MySQL初阶专栏MySQL初阶MySQL进阶专栏MySQL进阶计算机网络专栏计算机网络C语言专栏C语言欢迎点赞 收藏⭐ 留言发现错误欢迎指正✨脚踏实地持续深耕奔赴自己的目标✨----- 分割线 -------游标与条件处理程序1. 游标cursor1.1 游标完整四步声明、open、fetch、close1.2 游标基础示例代码1.3 游标缺点内存、不适合大表2. 条件处理程序 HANDLER2.1 语法讲解 DECLARE … HANDLER2.2 游标必踩坑fetch读完数据报1329报错HANDLER处理结束标记2.3 HANDLER的触发时机、continue和exit区别3. 条件处理程序 HANDLER3.1 游标 条件处理程序完整可运行存储过程(逐行遍历表并退出~)前言这里是小谢同学整理有关MySQL中游标的概念。笔记用于自我复盘巩固有错误欢迎大家指出专栏还有 Java、网络、C 语言系列笔记欢迎翻阅.同时也希望这篇文章能够帮助到你~1. 游标cursorMySQL 游标是一种数据库对象用于在存储过程或函数中逐行遍历查询结果集以便对每条记录进行处理。游标Cursor不是单独的 SELECT 语句而是由 SELECT 查询返回的结果集的指针。它允许程序逐行访问数据而不是一次性处理整个结果集这在处理大量数据或需要对每行执行复杂逻辑时非常有用MySQL 中的游标只能在存储过程和函数中使用。1.1 游标完整四步声明、open、fetch、close游标必须在条件处理程序之前被声明,并且变量必须在游标活条件处理程序之前被声明例如:我们想在一个存储过程中定义变量,我们需要在写存储过程中最前面先定义出我们所需要的变量如果后续我们想要添加某一个变量,我们可以直接在没有创建存储过程之前来添加,方便进行统一管理变量-游标-条件处理语句语法:-- 1.声明游标DECLAREcursor_nameCURSORFORselect_statement;-- 2.打开游标OPENcursor_name;-- 3.读取一行FETCHcursor_nameINTOvar_name[,var_name]...;-- 4.关闭游标CLOSEcursor_name;解释select_statement: 查询语句cursor_name : 游标名称var_name 读取对应的字段var_name [, var_name] … :查询放入的变量1.2 游标基础示例代码例如:传入班级编号,查询学生表中属于该班级学生的信息,并将符合条件的学生信息写入一张新表中;新表及字段t_student_class(id,student_name,class_name)实现逻辑:定义变量来接收查询结果集中的每一列的值声明游标创建新表开启游标从游标中获取结果集中的记录插入新表关闭游标对应表的查询结果:class:student:DELIMITER//CREATEPROCEDUREp7(INclass_idINT)BEGIN-- 创建我们所需要的变量-- 学生姓名DECLAREstudent_nameVARCHAR(20);-- 班级名字DECLAREclass_namevarchar(20);-- 声明游标DECLAREs_cursorCURSORFORSELECTs.name,ds.nameFROMstudentASsJOINclassASdsONs.class_idds.idwhereds.idclass_id;-- 创建新表CREATETABLEIFNOTEXISTSt_student_class(idINTPRIMARYKEYAUTO_INCREMENT,student_nameVARCHAR(20),class_nameVARCHAR(20));-- 打开游标OPENs_cursor;WHILETRUEDO-- 获取游标的内容FETCHs_cursorINTOstudent_name,class_name;-- 插入新表INSERTINTOt_student_classVALUES(null,student_name,class_name);ENDWHILE;END//DELIMITER;CALLp7(1);此处报错了:1329的典型错误由于while循环的退出条件是true此时是⼀个死循环当游标遍历完成之后继续向后遍历发现没有记录所以报错可以通过条件处理程序解决我们此时怎么解决这个问题?答案: 条件处理程序 HANDLER1.3 游标缺点内存、不适合大表消耗内存OPEN 的时候会把全部查询结果集加载到内存数据越多占用内存越高。性能差不适合大表游标是逐行处理行越多速度越慢千万级大表严禁游标。MySQL 设计优先集合操作能用UPDATE / INSERT ... SELECT批量就不要游标逐行。只能在存储过程、存储函数内部使用SQL 语句不能直接写游标。 返回目录2. 条件处理程序 HANDLER定义条件:事先定义程序执行过程中可能遇到的问题处理程序定义了在遇到问题的时候采取的处理方式使⽤条件处理程序保证存储过程或函数在遇到警告或错误时能继续执⾏可以增强程序处理问题的能⼒避免程序异常停⽌运⾏。2.1 语法讲解 DECLARE ... HANDLER语法:DECLAREhandler_actionHANDLERFORcondition_value[,condition_value]...statement;handler_action: {CONTINUE-- 继续执行当前程序|EXIT-- 终止执行当前程序} condition_value: { mysql_error_code-- MySQL错误码|SQLSTATE[VALUE]sqlstate_value-- 状态码|SQLWARNING-- 所有以01开头的SQLSTATE代码|NOTFOUND-- 所有以02开头的SQLSTATE代码|SQLEXCEPTION-- 所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE代码}mysql_error_code数字错误码SQLSTATE [VALUE] sqlstate_value5 位状态字符串SQLWARNING → 匹配所有01开头 SQLSTATE全部警告类不会终止程序的警告。NOT FOUND → 匹配所有02开头 SQLSTATE(最典型就是02000FETCH 游标已经读到数据集末尾找不到下一行。)SQLEXCEPTION除去 01 开头 (SQLWARNING)、02 开头 (NOT FOUND) 之外剩下全部错误。比如主键冲突、表不存在、语法错误全部归 SQLEXCEPTION。2.2 游标必踩坑fetch读完数据报1329报错HANDLER处理结束标记我们上述所见到的while循环写成死循环的情况,此时就出现了1329错误的状态码;原因归根结底就是:我们没有写条件处理程序而导致程序不能正常执行~2.3 HANDLER的触发时机、continue和exit区别类型行为适用场景CONTINUE捕获异常执行处理代码继续向下跑仅仅记录错误存储过程还要继续执行后续逻辑EXIT捕获异常执行处理代码立刻退出当前 begin‑end 块出错直接结束流程不再执行后面代码触发时机只有执行语句抛出对应条件时才触发 handler不是提前检测。游标 fetch 拿不到数据那一刻触发 NOT FOUND。 返回目录3. 条件处理程序 HANDLER使用条件处理程序来解决while循环出现的问题,防止游标在末尾而出现的问题:DELIMITER//CREATEPROCEDUREp7(INclass_idINT)BEGIN-- 创建我们所需要的变量-- 学生姓名DECLAREstudent_nameVARCHAR(20);-- 班级名字DECLAREclass_namevarchar(20);-- 创建判断条件DECLAREis_doneboolDEFAULTFALSE;-- 声明游标DECLAREs_cursorCURSORFORSELECTs.name,ds.nameFROMstudentASsJOINclassASdsONs.class_idds.idwhereds.idclass_id;-- 创建条件处理程序DECLARECONTINUEHANDLERFORNOTFOUNDSETis_done :TRUE;-- 创建新表CREATETABLEIFNOTEXISTSt_student_class(idINTPRIMARYKEYAUTO_INCREMENT,student_nameVARCHAR(20),class_nameVARCHAR(20));-- 打开游标OPENs_cursor;WHILENOTis_doneDO-- 获取游标的内容FETCHs_cursorINTOstudent_name,class_name;-- 插入新表INSERTINTOt_student_classVALUES(null,student_name,class_name);ENDWHILE;END//DELIMITER;CALLp7(1);SELECT*FROMt_student_class;但是此时问题又来了:为什么最后一条数据出现了两次?SELECTs.name,ds.nameFROMstudentASsJOINclassASdsONs.class_idds.idwhereds.id1;我们明明知道这里只有4条数据,但是为什么出现了5条?原因是:当游标执行到末尾时,再次移动会触发:1329报错,而我们此时处理方式是continue,让程序继续执行,此时游标就会指向最后一行的位置,执行完,然后退出循环此时就出现了,最后一行的数据重复了一次;当然如果我们想要合理的输出结果,我们需要使用LOOP循环来做3.1 游标 条件处理程序完整可运行存储过程(逐行遍历表并退出~)DELIMITER//CREATEPROCEDUREp7(INclass_idINT)BEGIN-- 创建我们所需要的变量-- 学生姓名DECLAREstudent_nameVARCHAR(20);-- 班级名字DECLAREclass_namevarchar(20);-- 创建判断条件DECLAREis_doneboolDEFAULTFALSE;-- 声明游标DECLAREs_cursorCURSORFORSELECTs.name,ds.nameFROMstudentASsJOINclassASdsONs.class_idds.idwhereds.idclass_id;-- 创建条件处理程序DECLARECONTINUEHANDLERFORNOTFOUNDSETis_done :TRUE;-- 创建新表CREATETABLEIFNOTEXISTSt_student_class(idINTPRIMARYKEYAUTO_INCREMENT,student_nameVARCHAR(20),class_nameVARCHAR(20));-- 打开游标OPENs_cursor;read_loop:LOOP-- 获取FETCHs_cursorINTOstudent_name,class_name;IFis_doneTHENLEAVEread_loop;ENDIF;-- 插入数据INSERTINTOt_student_classVALUES(null,student_name,class_name);ENDLOOPread_loop;END//DELIMITER;此时的结果就符合我们预想中的效果了:核心要点复盘DECLARE顺序普通变量 →HANDLER条件处理器 →CURSOR游标顺序颠倒直接语法报错NOT FOUND就是 fetch 读完所有行的信号不要捕获报错退出用标记变量 LEAVE跳出循环游标不要滥用数据库是集合运算尽量用 SQL 批量少用逐行游标逻辑。 返回目录
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。