leave必须带已声明的标签,否则报error 1064;仅能跳出同作用域内显式定义的loop或begin块,不可跨层跳转,且跳出时不自动回滚事务或关闭游标。

LEAVE 必须带标签,不写就报错 ERROR 1064
MySQL 的 LEAVE 不是独立语句,它必须后跟一个已声明的标签名,否则直接触发语法错误 ERROR 1064 (42000)。常见错误写法如 LEAVE; 或 LEAVE my_loop;(但没声明 my_loop:),都会失败。
正确做法是在循环或 BEGIN 块前显式加冒号定义标签:
-
outer_loop: LOOP→ 后续可用LEAVE outer_loop; -
proc_body: BEGIN→ 可用LEAVE proc_body;直接退出整个过程体 - 标签名区分大小写,且不能与变量、游标、过程名重名,否则可能触发
ERROR 1305 (42000): PROCEDURE does not exist
嵌套循环中 LEAVE 只能跳出当前作用域标签
MySQL 的 LEAVE 不支持跨层跳转。比如在 inner_loop: LOOP 内写 LEAVE outer_loop;,而 outer_loop 标签只定义在中间一层 BEGIN 中,内层根本不可见——这时要么报错,要么静默跳错位置。
安全做法只有两种:
- 把外层标签(如
outer_loop:)定义在存储过程最外层BEGIN之前,确保所有嵌套层级都能引用 - 改用标志变量(如
should_exit_outer BOOLEAN DEFAULT FALSE),在内层设为TRUE,外层循环每次迭代前检查并配合LEAVE
尤其注意:如果 LEAVE 跳出的是含游标的循环,务必在 LEAVE 前手动 CLOSE cur_name;,否则游标资源泄漏。
ITERATE 容易导致无限循环,关键在计数器位置
ITERATE 类似 continue,但它不会自动推进循环变量。典型坑点是:在 WHILE 或 LOOP 中,ITERATE 执行后直接跳回开头,若此时计数器还没更新,就会卡死。
例如这段代码会无限循环:
my_while: WHILE i <p>问题出在 <code>ITERATE</code> 后没执行 <code>SET i = i + 1;</code>。修复方式只有两个:</p>
- 把计数器更新提到
ITERATE前(如先SET i = i + 1;再判断是否ITERATE) - 改用
REPEAT结构,把条件判断放在末尾,天然规避该问题
LEAVE 跳出 BEGIN 块时事务不会自动回滚
用 LEAVE proc_body; 退出整个过程体很便捷,但容易忽略副作用:MySQL 不会因 LEAVE 自动触发 ROLLBACK,也不会清理已打开的游标或释放锁。
真实场景中,这种“快速失败”常用于参数校验:
proc_body: BEGIN IF p_id IS NULL THEN LEAVE proc_body; END IF; START TRANSACTION; -- 后续操作... END
但若 LEAVE 发生在 START TRANSACTION 之后、COMMIT 之前,就必须手动补 ROLLBACK;,否则事务处于悬挂状态,可能阻塞其他操作。更稳妥的做法是:把校验逻辑放在事务开始前,或用 DECLARE EXIT HANDLER 统一兜底。











