leave必须配合显式声明的标签使用,否则报错;仅能跳出当前标签所在层级,不可穿透嵌套;可跳出循环或带标签的begin块,但需注意事务、游标清理及handler作用域隔离。

LEAVE 不是万能跳转开关,它必须配合显式标签使用,否则直接报错;跳不出预期层级、提前终止循环、甚至跳出整个存储过程,根源几乎都出在标签声明或作用域误用上。
LEAVE 必须带标签,不写标签会语法错误
MySQL 要求 LEAVE 后面紧跟一个已声明的标签名,不能省略,也不能写错拼写。没有标签的 LEAVE 会被解析为语法错误(ERROR 1064)。
-
LEAVE后面必须是真实存在的标签,且该标签需用label_name: LOOP或label_name: BEGIN显式定义 - 标签名区分大小写,且不能与变量、游标、存储过程名同名,否则触发
ERROR 1305 (42000): PROCEDURE does not exist - 常见错误写法:
LEAVE;或LEAVE my_loop;(但未声明my_loop:) - 正确写法示例:
outer_loop: LOOP ... IF done THEN LEAVE outer_loop; END IF; ... END LOOP;
嵌套循环中 LEAVE 只能跳出当前标签所在层级
MySQL 的 LEAVE 无法“穿透”嵌套层级自动跳到外层——它只认紧邻的、同作用域内定义的标签。想从内层跳出外层循环,必须把外层标签定义在更外层作用域(比如整个存储过程体顶部),否则会报错或跳错位置。
- 错误做法:在
inner_loop内写LEAVE outer_loop,但outer_loop标签只在中间一层定义,内层不可见 - 安全做法:把
outer_loop定义在存储过程开头的BEGIN前,确保所有嵌套层级都能引用 - 更稳妥替代:用标志变量(如
should_break_outer BOOLEAN DEFAULT FALSE)配合ITERATE或二次判断,避免跨层LEAVE风险 - 切记:不要在内层
LEAVE outer_loop后遗漏CLOSE cur_outer,否则游标资源泄漏
LEAVE 可以跳出 BEGIN...END 程序体,不只是循环
只要给 BEGIN 加了标签(如 proc_body: BEGIN),LEAVE proc_body 就能直接退出整个存储过程逻辑,类似早期语言里的 goto exit。这适合做快速失败处理,但容易掩盖流程意图。
- 适用场景:参数校验失败、关键资源不可用、前置条件不满足时立即退出
- 示例:
proc_body: BEGIN IF p_id IS NULL THEN LEAVE proc_body; END IF; ... END - 风险点:过度使用会让逻辑跳跃难追踪,尤其和游标、事务混用时,可能跳过
ROLLBACK或CLOSE - 注意:
LEAVE跳出程序体不会自动回滚事务,需手动加ROLLBACK或确保在LEAVE前已完成必要清理
游标 + LEAVE 组合最容易踩的坑是 handler 作用域污染
根本问题在于 DECLARE CONTINUE HANDLER FOR NOT FOUND 是全局作用域的——只要任意一个 FETCH 遇空,就设 done = TRUE,导致外层循环误判退出。这不是 LEAVE 的错,但常被归咎于它。
- 每个游标必须配独立状态变量(如
done_outer、done_inner),不能共用done - 每个游标声明后,立刻跟专属 handler:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done_outer = TRUE - 内层游标
OPEN前,务必重置SET done_inner = FALSE,否则残留值会让本次FETCH直接跳过 - 嵌套游标里重复
OPEN会硬性报错ERROR 1326 (HY000): Cursor is not open,本质是上一轮已CLOSE,再OPEN不被允许
真正难的不是写对 LEAVE 语法,而是理清标签作用域、handler 作用域、游标生命周期三者的交叠关系。哪怕一行 LEAVE,背后可能牵动整个执行流的稳定性。











