declare condition必须放在begin…end块最开头,且所有declare语句(变量、条件、游标、处理器)须按序置于可执行语句之前,否则报error 1064;sqlstate值须为5字符单引号字符串,条件名在handler中须严格一致、不加引号、大小写敏感。

DECLARE CONDITION必须放在BEGIN…END块最开头
MySQL要求所有DECLARE语句(包括DECLARE CONDITION和DECLARE HANDLER)必须出现在存储过程或函数的BEGIN…END块内、任何可执行语句之前。一旦你写了SET、INSERT或SELECT,再声明条件就会报错:ERROR 1064 (42000): You have an error in your SQL syntax。
常见错误写法:
BEGIN SET @x = 1; DECLARE no_such_table CONDITION FOR SQLSTATE '42S02'; -- ❌ 报错:DECLARE在可执行语句之后 END
正确顺序应为:
- 先声明变量(
DECLARE var_name type DEFAULT ...) - 再声明条件(
DECLARE condition_name CONDITION FOR ...) - 然后声明处理程序(
DECLARE CONTINUE HANDLER FOR ...) - 最后才是
SET、INSERT等执行语句
SQLSTATE值必须是5字符字符串,不能漏引号或写错格式
SQLSTATE是ANSI标准的5位错误码,如表不存在是'42S02',主键冲突是'23000'。它**必须用单引号包裹**,且长度严格为5。写成42S02(无引号)、'42S020'(6位)、'HY000'(虽然合法但太宽泛)都会导致条件不触发或语法错误。
示例对比:
- ✅ 正确:
DECLARE table_missing CONDITION FOR SQLSTATE '42S02'; - ❌ 错误:
DECLARE table_missing CONDITION FOR SQLSTATE 42S02;(被当作文本标识符解析) - ❌ 错误:
DECLARE table_missing CONDITION FOR SQLSTATE '42S020';(长度超限) - ⚠️ 不推荐:
DECLARE generic_error CONDITION FOR SQLSTATE 'HY000';(匹配范围过大,掩盖具体问题)
处理程序里的condition_value要和CONDITION名称严格一致
定义好DECLARE table_missing CONDITION FOR SQLSTATE '42S02';后,后续DECLARE HANDLER中必须直接使用table_missing这个名称——不能拼错、不能加引号、不能大小写混用(MySQL在大多数配置下对条件名大小写敏感)。
典型陷阱:
- ✅
DECLARE CONTINUE HANDLER FOR table_missing SET @err_msg = 'Table not found'; - ❌
DECLARE CONTINUE HANDLER FOR 'table_missing' ...(加引号就变成字符串字面量,不是条件引用) - ❌
DECLARE CONTINUE HANDLER FOR TABLE_MISSING ...(全大写,若原声明是小写则不匹配) - ❌
DECLARE CONTINUE HANDLER FOR 42S02 ...(绕过条件名,直接写错误码——语法虽通,但失去命名语义和复用性)
用条件名而非裸错误码,好处是逻辑解耦:改错因只需改DECLARE CONDITION一行,所有HANDLER自动生效。
CONTINUE和EXIT行为差异直接影响事务边界
CONTINUE让错误发生后继续执行后续语句;EXIT则立即跳出当前BEGIN…END块。这在事务中尤为关键——比如你在一个事务里连续插入两条记录,第二条失败:
- 用
CONTINUE:第一条已提交(若自动提交开启),第二条报错后仍会执行第三条语句 - 用
EXIT:第二条失败 → 立即退出块 → 后续语句不执行,但**不会自动回滚**,需手动ROLLBACK或依赖外部事务控制
所以实际中更常见组合是:
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL; -- 或 SET @ret = -1;
END;
而单独用CONTINUE适合“跳过单条失败操作”的场景,比如批量导入时忽略重复主键记录。
真正容易被忽略的是:MySQL至今不支持UNDO handler,且NOT FOUND只捕获游标结束等特定流程类异常,不是所有“查不到”都算NOT FOUND——比如SELECT ... INTO没结果会报ERROR 1329 (02000),这才属于NOT FOUND范畴。











