• GreatSQL社区原创内容未经受权不得随便应用,转载请分割小编并注明起源。

内容提纲

一、测试环境搭建

二、执行过程解析

三、注意事项

一、测试环境搭建

首先创立一张表,并插入几行数据字段:

CREATE TABLE t (s1 INT, s2 char(100),PRIMARY KEY (s1));INSERT INTO t values(1,'aaa');INSERT INTO t values(2,'bbb');INSERT INTO t values(3,'ccc');

接着创立存储过程,这里的v_total用于判断数据行数。

因为MySQL游标获取完后,最初一行没有退出机制。所以不进行判断是否取完最初一行,就持续取数会产生报错。

DELIMITER ;;  CREATE PROCEDURE test_mysql_cursor_loop()    BEGIN      declare v_total int default 0;       declare i int default 0;       declare str1 int;      declare str2 varchar(255);      DECLARE stuCursor CURSOR FOR SELECT s1,s2 FROM t;      select count(s2) into v_total from t;      OPEN stuCursor;      stuLoop:LOOP        IF i = v_total THEN LEAVE stuLoop; end if;        FETCH stuCursor INTO str1,str2;          SELECT str1,str2;          set i = i+1;      end loop stuLoop;    END;;DELIMITER ;

二、执行过程解析

这个存储过程在MySQL外部转化为存储过程指令如下:

mysql> show PROCEDURE code test_mysql_cursor_loop;+-----+---------------------------------------------+| Pos | Instruction                                 |+-----+---------------------------------------------+|   0 | set v_total@0 0                             ||   1 | set i@1 0                                   ||   2 | set str1@2 NULL                             ||   3 | set str2@3 NULL                             ||   4 | cpush stuCursor@0: SELECT s1,s2 FROM t      ||   5 | stmt "select count(s2) into v_total from t" ||   6 | copen stuCursor@0                           ||   7 | jump_if_not 9(9) (i@1 = v_total@0)          ||   8 | jump 13                                     ||   9 | cfetch stuCursor@0 str1@2 str2@3            ||  10 | stmt "SELECT str1,str2"                     ||  11 | set i@1 (i@1 + 1)                           ||  12 | jump 7                                      ||  13 | cclose stuCursor@0                          ||  14 | cpop 1                                      |+-----+---------------------------------------------+15 rows in set (0.00 sec)

其中:

  • v_total@0的 @0 代表这是第一个自定义变量。
  • stuCursor@0的 @0 代表这是第一个cursor变量。

从指令能够看出cursor的运行须要通过几个过程:

1、cpush

这个用于注册一个cursor,初始化堆栈。

2、copen

这里会先运行SELECT s1,s2 FROM t指令,让cursor取得表的列信息,而后调用cpush,通过cpush->open来关上一个cursor,用于后续获取表数据。

3、cfetch

这个用于从cursor获取的数据赋值给自定义变量str1,str2,而后传递给client端显示。留神到这里用了jump 7来循环取数据。

4、cclose

敞开cursor。

5、cpop

把以后cursor从堆栈开释掉。

下面循环取数和退出机制如下:

jump_if_not 9(9) (i@1 = v_total@0)用于判断i@1是否等于v_total@0,如果不等于的话以后指令就跳转到第9个指令,继续执行cfetch。

如果i@1等于v_total@0的话就继续执行下一条jump 13敞开cursor退出以后循环。set i@1 (i@1 + 1)用于计数,jump 7用于持续循环取数。

三、注意事项

str1和str2的类型和数量必须与declare cursor的统一,如果申明不正确就会导致cfetch出错。

因为declare str1和str2之后,mysql就会对这两个列建设一张长期表,当cfetch数据之后就会把数据存入这张表,后续用户select的时候就从这张长期表取数据来显示,所以就必须进行正确的变量申明。

Enjoy MySQL :)

文章举荐:

GreatSQL MGR FAQ
https://mp.weixin.qq.com/s/J6...

万答#12,MGR整个集群挂掉后,如何能力主动选主,不必手动干涉
https://mp.weixin.qq.com/s/07...

『2021数据技术嘉年华·ON LINE』:《MySQL高可用架构演进及实际》
https://mp.weixin.qq.com/s/u7...

一条sql语句慢在哪之抓包剖析
https://mp.weixin.qq.com/s/AY...

万答#15,都有哪些状况可能导致MGR服务无奈启动
https://mp.weixin.qq.com/s/in...

技术分享 | 为什么MGR一致性模式不举荐AFTER
https://mp.weixin.qq.com/s/rN...

对于 GreatSQL

GreatSQL是由万里数据库保护的MySQL分支,专一于晋升MGR可靠性及性能,反对InnoDB并行查问个性,是实用于金融级利用的MySQL分支版本。

Gitee:
https://gitee.com/GreatSQL/Gr...

GitHub:
https://github.com/GreatSQL/G...

Bilibili:
https://space.bilibili.com/13...

微信&QQ群:
可搜寻增加GreatSQL社区助手微信好友,发送验证信息“加群”退出GreatSQL/MGR交换微信群

QQ群:533341697
微信小助手:wanlidbc

本文由博客一文多发平台 OpenWrite 公布!