MySQL存储过程中的游标是一种临时的结果集指针,用于在存储过程内部逐行遍历SELECT语句返回的多行查询结果,适合需要实现逐行处理数据、批量执行操作的场景。比如需要批量更新符合特定条件的多条记录,或者逐行校验数据合法性时,就可以结合游标来完成。

游标的基本使用流程
在MySQL存储过程中使用游标需要遵循固定的步骤,顺序不能颠倒,整体流程如下:
- 声明游标:定义游标关联的查询语句
- 声明继续处理程序:定义当游标遍历完所有数据时的处理逻辑
- 打开游标:执行游标关联的查询,将结果集加载到游标中
- 取值:从游标中取出当前行的数据赋值给变量
- 处理数据:对取出的变量执行对应的业务逻辑
- 关闭游标:释放游标占用的资源
游标相关语法说明
1. 声明游标
使用DECLARE语句声明游标,语法格式如下:
-- 声明游标,关联查询用户表的id和积分 DECLARE cur_user CURSOR FOR SELECT user_id, score FROM user_info WHERE status = 1;
2. 声明继续处理程序
游标遍历完所有数据后,再次执行FETCH会触发NOT FOUND条件,需要提前声明处理程序来跳出循环,语法如下:
-- 当游标无更多数据时,设置结束标记变量为1 DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
3. 打开和关闭游标
打开游标会执行关联的查询语句,关闭游标会释放相关资源,语法如下:
-- 打开游标 OPEN cur_user; -- 关闭游标 CLOSE cur_user;
4. 取值操作
使用FETCH语句从游标中取出当前行的数据,赋值给预先声明的变量,语法如下:
-- 从游标中取数据,赋值给变量v_user_id和v_score FETCH cur_user INTO v_user_id, v_score;
完整存储过程案例:批量更新用户等级
下面通过一个实际案例演示游标的完整使用,需求是遍历所有有效用户,根据用户的积分更新对应的用户等级,积分大于等于1000为等级3,500到999为等级2,小于500为等级1。
-- 创建存储过程更新用户等级
DELIMITER //
CREATE PROCEDURE update_user_level()
BEGIN
-- 声明变量
DECLARE v_user_id INT;
DECLARE v_score INT;
DECLARE done INT DEFAULT 0;
-- 声明游标,关联有效用户的id和积分
DECLARE cur_user CURSOR FOR SELECT user_id, score FROM user_info WHERE status = 1;
-- 声明继续处理程序,游标无数据时设置done为1
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- 打开游标
OPEN cur_user;
-- 循环遍历游标
read_loop: LOOP
-- 从游标取数据
FETCH cur_user INTO v_user_id, v_score;
-- 如果done为1,说明没有更多数据,跳出循环
IF done = 1 THEN
LEAVE read_loop;
END IF;
-- 根据积分更新用户等级
IF v_score >= 1000 THEN
UPDATE user_info SET user_level = 3 WHERE user_id = v_user_id;
ELSEIF v_score >= 500 THEN
UPDATE user_info SET user_level = 2 WHERE user_id = v_user_id;
ELSE
UPDATE user_info SET user_level = 1 WHERE user_id = v_user_id;
END IF;
END LOOP;
-- 关闭游标
CLOSE cur_user;
END //
DELIMITER ;
-- 调用存储过程执行批量更新
CALL update_user_level();
游标使用注意事项
- 游标声明必须放在变量声明之后,处理程序声明之前,否则会报语法错误
- 游标关联的查询语句返回的列数,必须和
FETCH赋值变量的数量、类型一致,否则会取值失败 - 游标使用完成后一定要及时关闭,避免占用数据库连接资源
- 如果遍历的数据量非常大,游标逐行处理的方式效率较低,优先考虑用批量SQL语句实现,游标更适合复杂的逐行逻辑处理场景
- 处理程序中的
done变量初始化要放在游标声明之前,避免触发异常
游标是存储过程中处理多行结果集的有效工具,但不需要逐行处理的场景尽量不用,优先选择集合式的SQL操作,性能会更好。