LEAVE必须配合显式声明的标签使用,否则报错ERROR 1308;仅能跳出当前标签所在层级,不可穿透嵌套;可跳出循环或带标签BEGIN块,但需手动CLOSE游标并确保标签定义可见。

LEAVE 必须配合标签使用,否则报错
直接写 LEAVE 会触发 ERROR 1308 (42000): LEAVE with no matching label。MySQL 要求每个 LEAVE 都指向一个明确的带名代码块(即标签),哪怕只有一层循环。
常见错误写法:WHILE i —— 这里没定义标签,<code>LEAVE 不知道要跳到哪。
- 正确做法:在
WHILE前加标签名,比如loop_label: WHILE i - 标签名必须唯一且不能是保留字(如
main、outer、read_loop都可以) - 标签作用域仅限于它包裹的语句块,不能跨
BEGIN...END使用
WHILE / REPEAT / LOOP 三种循环的退出方式一致
别被语法差异误导:无论用 WHILE、REPEAT 还是裸 LOOP,退出逻辑都靠 LEAVE 标签名,没有例外。
例如,REPEAT 看似自带终止条件(UNTIL),但提前退出仍需 LEAVE:
DECLARE i INT DEFAULT 0;
repeat_label: REPEAT
SET i = i + 1;
IF i = 3 THEN
LEAVE repeat_label; -- 不等 UNTIL 触发就跳出
END IF;
UNTIL i >= 5
END REPEAT;-
WHILE:条件在头部判断,适合“先检查再执行”场景 -
REPEAT:条件在尾部判断,至少执行一次,适合“先干再验”逻辑 -
LOOP:无内置条件,完全依赖LEAVE控制,容易写成死循环,慎用
游标遍历中 LEAVE 后必须手动 CLOSE 游标
很多人以为 LEAVE 会自动清理资源,但 MySQL 不会自动关闭已打开的游标。漏掉 CLOSE 可能导致后续调用报 ERROR 1326 (HY000): Cursor is already open 或连接资源泄漏。
标准写法模板:
DECLARE done INT DEFAULT FALSE; DECLARE cur CURSOR FOR SELECT id FROM users; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; <p>OPEN cur; cursor_loop: LOOP FETCH cur INTO @id; IF done THEN CLOSE cur; -- 必须放在这里 LEAVE cursor_loop; END IF; -- 处理 @id ... END LOOP;
-
CLOSE要在LEAVE之前执行,否则跳出去就来不及关了 - 如果循环体里有多个退出点(比如不同条件触发),每个都要配
CLOSE+LEAVE - 不要指望存储过程结束时自动关游标——MySQL 不保证
想整个存储过程提前退出?用 LEAVE 标签 + BEGIN 标签
所谓“优雅退出循环”,有时真实需求是“发现异常立刻终止整个过程”,而不是只跳出当前循环。这时可以把最外层 BEGIN 加上标签,然后 LEAVE 它。
例如校验失败后不继续扣库存、不更新状态:
main: BEGIN
DECLARE order_exists INT DEFAULT 0;
SELECT COUNT(*) INTO order_exists FROM orders WHERE id = in_order_id;
IF order_exists = 0 THEN
LEAVE main; -- 直接退出整个存储过程,后面全跳过
END IF;
<p>-- 后续业务逻辑(扣库存、改状态等)
END;- 这种写法比嵌套多层
IF更清晰,也避免冗余的ELSE分支 - 注意:标签名(如
main)必须紧贴BEGIN,不能换行或加空格 - 如果存储过程中有多个
BEGIN...END块,每个都可以独立打标签,LEAVE只影响对应那一层
真正容易被忽略的是标签的强制性和游标的手动释放——它们不是可选项,而是 MySQL 的硬性规则。写完记得检查两点:所有 LEAVE 是否都有匹配标签,所有 OPEN 后是否都有对应的 CLOSE。


















