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

MySQL游标(cursor)详解

一:游标概述

 1、游标的概念

游标(Cursor)是数据库系统中的一种对象,它提供了一种机制,使应用程序能够逐行访问SQL查询返回的结果集。游标充当一个指针,指向查询结果集中的当前行,允许应用程序按需对数据进行检索和操作。

游标是将集合处理方式转换为面向过程的记录处理方式的一种重要工具,特别适用于需要逐行处理的复杂业务逻辑实现。

2、游标的必要性

在以下场景中,游标的使用尤为必要:

  • 复杂数据处理:需要基于当前记录状态执行条件逻辑的情况

  • 逐行操作:需要对结果集中的每一行执行特定操作时

  • 个性化处理:针对不同记录属性需要采取不同处理策略的情况

  • 统计与聚合:需要在过程中维护状态变量的复杂计算

示例场景:在学生成绩处理系统中,需要根据不同学生的成绩区间,给予不同的评价和建议。

3、游标的优缺点分析

优势:

  • 提供了对数据的逐行操作能力,增强了灵活性

  • 允许根据当前记录状态动态决定处理逻辑

  • 简化了需要依赖前一记录内容的计算实现

  • 为处理大型结果集提供了一种内存效率更高的方法

局限性:

  • 性能开销较大,相比集合操作效率较低

  • 增加了数据库服务器资源消耗

  • 代码复杂度增加

  • 潜在的并发问题和资源管理挑战

二:游标的操作流程

MySQL中的游标操作遵循以下规范化流程:

1、游标声明

DECLARE cursor_name CURSOR FOR select_statement;

声明游标定义了一个结果集,但不执行查询。此语句指定了游标名称和返回游标结果集的SELECT语句。

2、游标打开操作

OPEN cursor_name;

OPEN语句执行游标的SELECT查询,并使游标指向结果集中第一行之前的位置。

3、数据获取操作

FETCH cursor_name INTO variable_list;

 FETCH语句从游标当前位置检索下一行数据,并将其存储在指定的变量中,同时将游标移动到下一行。

4、游标关闭操作

CLOSE cursor_name;

CLOSE语句释放与游标相关的所有资源,但保留游标定义,以便后续可以再次打开。

5、处理游标结束情况

DECLARE CONTINUE HANDLER FOR NOT FOUND SET variable = value;

为NOT FOUND条件定义处理程序,确保在游标遍历完所有记录后能够正常退出循环。

三:学生成绩统计分析

 教务处需要计算每个学生的平均分和总分,用于排名和评优。

CREATE TABLE `t_student_summary` (`summary_id` int NOT NULL AUTO_INCREMENT,`sid` int NOT NULL COMMENT '学生编号',`sname` varchar(50) NOT NULL COMMENT '学生姓名',`total_score` decimal(8,2) NOT NULL COMMENT '总分',`avg_score` decimal(5,2) NOT NULL COMMENT '平均分',`course_count` int NOT NULL COMMENT '课程数量',`create_time` datetime NOT NULL,PRIMARY KEY (`summary_id`)
);

实现存储过程:

DELIMITER $$
CREATE PROCEDURE calculate_student_scores()
BEGIN-- 声明变量DECLARE v_sid INT;DECLARE v_sname VARCHAR(50);DECLARE v_ssex CHAR(1);DECLARE v_total DECIMAL(8,2);DECLARE v_avg DECIMAL(5,2);DECLARE v_count INT;DECLARE done INT DEFAULT 0;-- 声明游标 - 获取所有学生信息DECLARE student_cursor CURSOR FORSELECT sid, sname, ssex FROM t_student ORDER BY sid;-- 设置结束标志DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;-- 清空统计表TRUNCATE TABLE t_student_summary;-- 打开游标OPEN student_cursor;-- 开始循环处理每个学生student_loop: LOOP-- 获取当前学生FETCH student_cursor INTO v_sid, v_sname, v_ssex;-- 检查是否结束IF done THENLEAVE student_loop;END IF;-- 计算该学生的成绩统计SELECT IFNULL(SUM(score), 0), IFNULL(AVG(score), 0), COUNT(*) INTO v_total, v_avg, v_countFROM t_scoreWHERE sid = v_sid;-- 写入统计表INSERT INTO t_student_summary (sid, sname, total_score, avg_score, course_count, create_time)VALUES (v_sid, v_sname, v_total, v_avg, v_count, NOW());END LOOP student_loop;-- 关闭游标CLOSE student_cursor;-- 显示统计结果,按平均分降序排列SELECT * FROM t_student_summary ORDER BY avg_score DESC;END $$
DELIMITER ;

四、成绩批量调整处理

发现评分标准有误差,需要对特定课程的所有学生成绩进行统一调整。

DELIMITER $$
CREATE PROCEDURE adjust_course_scores(IN p_cid INT, IN p_adjustment DECIMAL(5,2))
BEGIN-- 声明变量DECLARE v_sid INT;DECLARE v_current_score DECIMAL(5,2);DECLARE v_new_score DECIMAL(5,2);DECLARE done INT DEFAULT 0;-- 声明游标 - 获取指定课程的所有学生成绩DECLARE score_cursor CURSOR FORSELECT sid, scoreFROM t_scoreWHERE cid = p_cid;-- 设置结束标志DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;-- 创建临时表记录调整历史CREATE TEMPORARY TABLE IF NOT EXISTS temp_score_adjustments (sid INT,old_score DECIMAL(5,2),new_score DECIMAL(5,2));-- 打开游标OPEN score_cursor;-- 开始循环处理每个学生成绩score_loop: LOOP-- 获取当前学生成绩FETCH score_cursor INTO v_sid, v_current_score;-- 检查是否结束IF done THENLEAVE score_loop;END IF;-- 计算新成绩(加上调整分数,但不超过100分)SET v_new_score = LEAST(v_current_score + p_adjustment, 100);-- 更新成绩UPDATE t_scoreSET score = v_new_scoreWHERE sid = v_sid AND cid = p_cid;-- 记录调整历史INSERT INTO temp_score_adjustments (sid, old_score, new_score)VALUES (v_sid, v_current_score, v_new_score);END LOOP score_loop;-- 关闭游标CLOSE score_cursor;-- 删除临时表END $$
DELIMITER ;

五、游标常见问题

问题1:游标处理死循环

  • 原因:未正确设置NOT FOUND处理程序

  • 解决方案:确保声明CONTINUE HANDLER FOR NOT FOUND并正确设置循环终止条件

问题2:资源泄漏

  • 原因:未关闭游标

  • 解决方案:在处理完成后总是执行CLOSE语句释放资源

问题3:性能低下

  • 原因:游标循环中执行了过多复杂查询

  • 解决方案:优化查询,预先计算或使用临时表存储中间结果

问题4:游标结果集被修改

  • 原因:在游标循环中修改了游标查询的表

  • 解决方案:避免在处理过程中修改游标基于的表结构或索引字段

相关文章:

  • 3 提示词工程指南-提示词编辑 - 持续更新
  • LWIP_MQTT连接ONENET
  • Java 中常用队列用法详解
  • OpenGL shader开发实战学习笔记:第十一章 立方体贴图和天空盒
  • 计算机网络基础概论
  • Linux中docker容器拉取镜像失败解决方案
  • HCIP(OSPF )(2)
  • 第一篇:linux之虚拟环境与centos安装
  • 在ubuntu20.04上安装ros2
  • 【软考-系统架构设计师】OSI体系解析
  • 远程医疗系统安全升级:构建抗CC攻击的全方位防护网
  • SpringBoot_第十章(启动过程)
  • 代码学习总结(三)
  • 离散化--
  • 金融数据库转型实战读后感
  • 目标检测概述
  • AI在市场营销分析中的核心应用及价值,分场景详细说明
  • 【C++】深入浅出之继承
  • 召回率和精准率-找书的例子
  • 机器视觉在贴标机的应用
  • “75万买299元路由器”事件进展:重庆市纪委等三部门联合介入调查
  • 广东韶关一镇干部冲进交通事故火海救人,获授“见义勇为”奖励万元
  • 澎湃思想周报|欧洲胜利日之思;教育监控与学生隐私权争议
  • “饿了么”枣庄一站点两名连襟骑手先后猝死,软件显示生前3天每日工作超11小时
  • 江苏省委社会工作部部长等多人拟在省志愿服务联合会任职
  • 巴西总统卢拉将访华