概念

虽然我们也可以通过筛选条件 WHERE 和 HAVING,或者是限定返回记录的关键字 LIMIT 返回一条记录,但是,却无法在结果集中像指针一样,向前定位一条记录、向后定位一条记录,或者是随意定位到某一条记录,并对记录的数据进行处理。

这个时候,就可以用到游标。游标,提供了一种灵活的操作方式,让我们能够对结果集中的每一条记录进行定位,并对指向的记录中的数据进行操作的数据结构。游标让 SQL 这种面向集合的语言有了面向过程开发的能力。

在 SQL 中,游标是一种临时的数据库对象,可以指向存储在数据库表中的数据行指针。这里游标充当了指针的作用,我们可以通过操作游标来对数据行进行操作。

MySQL中游标可以在存储过程和函数中使用

游标使用的步骤

注意:

  • 游标必须在声明处理程序之前被声明,并且变量和条件还必须在声明游标或处理程序之前被声明
  • 如果我们想要使用游标,一般需要经历四个步骤。不同的 DBMS 中,使用游标的语法可能略有不同。

    第一步:游标声明

    在MySQL中,使用DECLARE关键字来声明游标,其语法的基本形式如下:
    1. DECLARE cursor_name CURSOR FOR select_statement;
    要使用 SELECT 语句来获取数据结果集,而此时还没有开始遍历数据,这里 select_statement 代表的是 SELECT 语句,返回一个用于创建游标的结果集。

    第二步:打开游标

    1. OPEN cursor_name
    当我们定义好游标之后,如果想要使用游标,必须先打开游标。打开游标的时候 SELECT 语句的查询结果集就会送到游标工作区,为后面游标的逐条读取结果集中的记录做准备。

第三步:使用游标(从游标中取的数据)

  1. FETCH cursor_name INTO var_name [, var_name] ...

这句的作用是使用 cursor_name 这个游标来读取当前行,并且将数据保存到 var_name 这个变量中,游标指针指到下一行。如果游标读取的数据行有多个列名,则在 INTO 关键字后面赋值给多个变量名即可。
注意

  • var_name必须在声明游标之前就定义好。
  • 游标的查询结果集中的字段数,必须跟 INTO 后面的变量数一致,否则,在存储过程执行的时候,MySQL 会提示错误。

    第四步:关闭游标

    1. CLOSE cursor_name
    有 OPEN 就会有 CLOSE,也就是打开和关闭游标。当我们使用完游标后需要关闭掉该游标。因为游标会占用系统资源,如果不及时关闭,游标会一直保持到存储过程结束,影响系统运行的效率。而关闭游标的操作,会释放游标占用的系统资源。

关闭游标之后,我们就不能再检索查询结果中的数据行,如果需要检索只能再次打开游标。

例子

需求:
创建存储过程“get_count_by_limit_total_salary()”,声明IN参数 limit_total_salary,DOUBLE类型;声明OUT参数total_count,INT类型。函数的功能可以实现累加薪资最高的几个员工的薪资值,直到薪资总和达到limit_total_salary参数的值,返回累加的人数给total_count。

  1. DELIMITER //
  2. CREATE PROCEDURE get_count_by_limit_total_salary(IN limit_total_salary DOUBLE,OUT total_count INT)
  3. BEGIN
  4. #声明局部变量
  5. DECLARE sum_sal DOUBLE DEFAULT 0.0; #记录累加的工资总额
  6. DECLARE emp_sal DOUBLE; #记录每一个员工的工资
  7. DECLARE emp_count INT DEFAULT 0;#记录累加的人数
  8. #1.声明游标
  9. DECLARE emp_cursor CURSOR FOR SELECT salary FROM employees ORDER BY salary DESC;
  10. #2.打开游标
  11. OPEN emp_cursor;
  12. REPEAT
  13. #3.使用游标
  14. FETCH emp_cursor INTO emp_sal;
  15. SET sum_sal = sum_sal + emp_sal;
  16. SET emp_count = emp_count + 1;
  17. UNTIL sum_sal >= limit_total_salary
  18. END REPEAT;
  19. SET total_count = emp_count;
  20. #4.关闭游标
  21. CLOSE emp_cursor;
  22. END //
  23. DELIMITER ;
  24. #调用
  25. CALL get_count_by_limit_total_salary(200000,@total_count);
  26. SELECT @total_count;

小结

游标是 MySQL 的一个重要的功能,为逐条读取结果集中的数据,提供了完美的解决方案。跟在应用层面实现相同的功能相比,游标可以在存储程序中使用,效率高,程序也更加简洁。

但同时也会带来一些性能问题,比如在使用游标的过程中,会对数据行进行加锁,这样在业务并发量大的时候,不仅会影响业务之间的效率,还会消耗系统资源,造成内存不足,这是因为游标是在内存中进行的处理。

建议:游标用完之后要及时关闭,这样才能提高系统的整体效率。