MySQL Cursor

495人浏览 / 0人评论

参考

https://blog.51cto.com/u_12260130/6178914

https://lifelmy.cn/post/2023_04_09_mysql_cursor/

定义

Cursor 就是游标,可以理解为 Java 集合迭代器的游标,或者数组的下标。在存储过程中对查询的数据进行处理时,由于 Select 返回的是个数据集,无法处理第一行、下一行、前十行的数据,除非每次修改 where 条件获得想要的那一条记录,而 Cursor 可以很方便的处理这种情况。

MySQL游标是只读的,不可滚动且不敏感的。

  • 只读:无法通过游标更新表中的数据。
  • 不可滚动:只能朝着一个方向挨个遍历,不能反向遍历;不能跳行或者跳转到特定行。
  • 不敏感:有两种光标:敏感型游标和不敏感游标。敏感型光标指向实际数据,而不敏感型光标使用数据的临时副本。敏感型游标比不敏感游标执行得更快,因为它不必创建临时数据副本。但是,其他连接所做的任何更改都将影响敏感光标正在使用的数据。MySQL游标是不敏感的。

比较适合在刷数据或迁移数据时使用。

使用

Cursor 的使用分为如下四步:

  • 声明游标
  • 打开游标
  • 获取数据
  • 关闭游标

声明游标

DECLARE cursor_name CURSOR FOR select_statement

注意:

  • 游标声明中,必须有一个 Select 语句;
  • Select 语句中不能包含 into 关键字;
  • 游标声明,必须在 handler 声明之前,在 变量 和 condition 声明之后;
  • 在一个代码块中可以声明多个游标,但是多个游标的名字不能相同。

打开游标

OPEN cursor_name

获取数据

FETCH cursor_name INTO var_name [, var_name] ...

注意:

  • fetch 中的 cursor_name 必须是开启状态;
  • fetch 语句中,var_name 的数量要与声明语句中 Select 查询列的数量一致,保证每个列都有变量接收。

使用 fetch 获取游标中 Select 语句的下一条记录,并将游标前进一步。如果查询到数据,就将每列对应的值赋值给相应变量;如果已经到了数据集末尾,没有数据可以获取了,会产生一个值为 '02000' 的 SQLSTATE (NOT FOUND),此时可以声明一个 handler 来处理这种情况。

如果我们在一个代码块中有多个游标,那么一个游标 fetch 时如果产生 NOT FOUND,handler 的触发可能会对另一个游标产生影响。如果想避免这种影响,可以在多个 BEGIG…END 代码块中分别声明各自的handler,然后再操作游标,保证互不影响。

关闭游标

CLOSE cursor_name
  • 如果关闭一个非开启状态的游标会报错;
  • 对于声明在一个 BEGIN…END 中的游标,如果没有显示的使用 close 去关闭的话,执行到 END 会自动关闭游标。

示例

如下示例中,我们声明了两个游标 cur1 和 cur2,分别查询 id、data 和 i 字段;还声明了一个 CONTINUE handler,当其中一个游标访问到数据集末尾时,设置变量 done 为 TRUE,用于控制循环退出。

其中几个注意点:

  • 声明游标必须在 handler 声明之前,在 变量 和 condition 声明之后;
  • 多个游标名称不能重复;
  • 使用游标前需要先打开游标;
  • 游标中 select 列的数量,与 fetch into 变量数量一样;
  • 使用完关闭游标。
CREATE PROCEDURE curdemo()
BEGIN
  DECLARE done INT DEFAULT FALSE;
  DECLARE a CHAR(16);
  DECLARE b, c INT;
  DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
  DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  OPEN cur1;
  OPEN cur2;

  read_loop: LOOP
    FETCH cur1 INTO a, b;
    FETCH cur2 INTO c;
    IF done THEN
      LEAVE read_loop;
    END IF;
    IF b < c THEN
      INSERT INTO test.t3 VALUES (a,b);
    ELSE
      INSERT INTO test.t3 VALUES (a,c);
    END IF;
  END LOOP;

  CLOSE cur1;
  CLOSE cur2;
END;

全部评论