MySQL——游标(cursor)

一、什么是游标?

游标(Cursor) 是MySQL中用于逐行处理查询结果集的数据库对象。它类似于指针,允许开发者在结果集中逐行移动,并对每一行数据进行特定操作。游标将传统的集合操作转换为面向过程的记录处理方式,特别适用于需要逐行逻辑判断或复杂计算的场景。

为什么需要游标?

  • 逐行处理:如根据每行数据动态生成计算结果或触发业务逻辑。

  • 复杂逻辑:需要基于当前行数据状态执行条件分支操作。

  • 个性化操作:不同记录需要不同的处理策略(如生成定制化报告)。


二、游标的优缺点:权衡使用场景

优点

  1. 灵活性强:支持逐行数据访问与操作。

  2. 内存高效:分批处理大型结果集,避免一次性加载内存溢出。

  3. 过程化控制:可在循环中结合条件判断和变量计算。

缺点

  1. 性能开销:比集合操作(如JOIN、子查询)效率低。

  2. 资源消耗:占用数据库连接资源,长时间未关闭可能导致阻塞。

  3. 复杂度高:代码量增加,调试和维护难度大。


三、游标操作流程:五步掌握核心用法

1. 声明游标

DECLARE cursor_name CURSOR FOR 
SELECT column1, column2 FROM table WHERE condition;
  • 作用:定义游标名称和关联的查询,不执行查询

2. 打开游标

OPEN cursor_name;
  • 作用:执行关联的SELECT语句,生成结果集。

3. 获取数据

FETCH cursor_name INTO var1, var2;
  • 作用:将当前行数据存入变量,游标下移一行。

4. 处理结束条件

DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
  • 作用:当FETCH无更多数据时触发,设置结束标志。

5. 关闭游标

CLOSE cursor_name;
  • 作用:释放游标占用的资源,必须显式调用


四、实战案例:游标典型应用场景

案例1:生成学生成绩评估报告

需求:为每个学生的每门课程生成等级和建议。

DELIMITER $$
CREATE PROCEDURE generate_grade_reports()
BEGIN
    DECLARE v_sid INT;
    DECLARE v_score DECIMAL(5,2);
    DECLARE done INT DEFAULT 0;
    
    -- 声明游标:获取所有学生成绩
    DECLARE grade_cursor CURSOR FOR
        SELECT sid, score FROM t_score;
    
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
    
    OPEN grade_cursor;
    grade_loop: LOOP
        FETCH grade_cursor INTO v_sid, v_score;
        IF done THEN LEAVE grade_loop; END IF;
        
        -- 根据分数生成等级
        CASE 
            WHEN v_score >= 90 THEN 
                INSERT INTO t_report VALUES (v_sid, 'A', '优秀');
            WHEN v_score >= 80 THEN 
                INSERT INTO t_report VALUES (v_sid, 'B', '良好');
            -- 更多条件...
        END CASE;
    END LOOP;
    CLOSE grade_cursor;
END $$
DELIMITER ;

案例2:统计学生总分与平均分

需求:逐学生计算总分、平均分并汇总。

DELIMITER $$
CREATE PROCEDURE calculate_student_stats()
BEGIN
    DECLARE v_sid INT;
    DECLARE v_total, v_avg DECIMAL;
    DECLARE done INT DEFAULT 0;
    
    -- 声明游标:遍历学生
    DECLARE student_cursor CURSOR FOR
        SELECT sid FROM t_student;
    
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
    
    OPEN student_cursor;
    student_loop: LOOP
        FETCH student_cursor INTO v_sid;
        IF done THEN LEAVE student_loop; END IF;
        
        -- 计算当前学生的统计值
        SELECT SUM(score), AVG(score) INTO v_total, v_avg
        FROM t_score WHERE sid = v_sid;
        
        INSERT INTO t_stats VALUES (v_sid, v_total, v_avg);
    END LOOP;
    CLOSE student_cursor;
END $$
DELIMITER ;

案例3:批量调整课程成绩

需求:为某课程所有学生成绩增加固定分值,不超过100分。

DELIMITER $$
CREATE PROCEDURE adjust_scores(IN course_id INT, IN adjust DECIMAL)
BEGIN
    DECLARE v_sid INT;
    DECLARE v_old_score DECIMAL;
    DECLARE done INT DEFAULT 0;
    
    -- 声明游标:获取指定课程成绩
    DECLARE score_cursor CURSOR FOR
        SELECT sid, score FROM t_score WHERE cid = course_id;
    
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
    
    OPEN score_cursor;
    adjust_loop: LOOP
        FETCH score_cursor INTO v_sid, v_old_score;
        IF done THEN LEAVE adjust_loop; END IF;
        
        -- 计算新成绩并更新
        UPDATE t_score SET score = LEAST(v_old_score + adjust, 100)
        WHERE sid = v_sid AND cid = course_id;
    END LOOP;
    CLOSE score_cursor;
END $$
DELIMITER ;

五、常见问题与解决方案

问题1:游标死循环

  • 现象:存储过程无法退出循环。

  • 原因:未正确处理NOT FOUND条件。

  • 解决:确保声明CONTINUE HANDLER并设置终止标志。

问题2:游标性能低下

  • 现象:处理速度慢,数据库负载高。

  • 原因:循环内执行复杂查询或大量计算。

  • 解决:预先计算中间结果,使用临时表存储数据。

问题3:资源泄漏

  • 现象:连接数异常增长,数据库响应变慢。

  • 原因:未显式关闭游标。

  • 解决:在结束处理后务必执行CLOSE


六、最佳实践与优化建议

  1. 限制使用场景:优先使用集合操作,仅在必须逐行处理时使用游标。

  2. 优化查询语句:游标关联的SELECT语句需高效,避免全表扫描。

  3. 批量提交事务:在循环内定期COMMIT,减少锁竞争。

  4. 资源及时释放:处理完成后立即关闭游标。

  5. 监控性能:使用EXPLAIN分析查询计划,检查执行时间。


七、总结

适用场景

  • 逐行数据校验(如格式检查)

  • 动态生成报告(如个性化评价)

  • 级联更新/删除(如历史数据迁移)

慎用场景

  • 大数据量处理(性能敏感)

  • 高并发业务(资源竞争激烈)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搬码红绿灯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值