MySQL RESIGNAL 怎样在存储程序中保留原始错误信息
来源:17golang原创
时间:2026-10-20 23:01:49 280浏览 收藏
MySQL 条件处理器执行记录或清理语句后,如果仍要向调用方传递触发处理器的原始错误,使用裸 RESIGNAL;,不要重新拼装一个通用 SIGNAL。需要记录原始诊断时,在处理器内使用 GET STACKED DIAGNOSTICS;需要有意修改某项信息时,再使用 RESIGNAL SET。
官方地址:https://www.mysql.com/
下面以 MySQL 8.4 为范围,使用主动触发的受控异常演示,不涉及生产表写入。示例未在本文环境执行;下文给出的都是语义预期和读者可复现的方法,不是实测数据或性能结论。
先记录错误三元组作为对照
假设一个存储过程需要记下失败原因,再把失败交给应用。如果统一改成“操作失败”,调用端可能失去用于分类的错误号。这里先把基线定义为三项:SQLSTATE、MYSQL_ERRNO、MESSAGE_TEXT。判断“保留原错”,不应只看客户端有没有显示一段文字。
| 观察项 | 用途 | 比较方法 |
|---|---|---|
| SQLSTATE | 条件类别 | 比较五字符状态值 |
| MYSQL_ERRNO | MySQL 错误标识 | 比较数字错误号 |
| MESSAGE_TEXT | 具体诊断文本 | 区分原文、主动改写与客户端展示 |
这是一套错误传递指标,不是压测指标。若没有采集耗时、吞吐和负载,就不能把“异常更完整”写成“性能提高”。对排障而言,先确认语义正确才有讨论其他代价的基础。
额外语句改变的是哪个诊断区
条件处理器激活时,诊断区有当前层与堆叠层。当前诊断区 CURRENT 可以被处理器中的后续语句改变;堆叠诊断区 STACKED 保存处理器激活时的条件信息。只在记录语句之后读取 CURRENT,就可能读到记录语句自己的诊断,而不是业务失败。
GET STACKED DIAGNOSTICS 用于读取原条件;RESIGNAL 用于重新向外传递条件。二者不是同一个动作。只把值读进变量,并不代表调用者会收到失败;裸 RESIGNAL 本身也不要求先读出这些变量。

在处理器里读取原条件再裸 RESIGNAL
下面的过程有两种模式:0 原样透传,1 只改写消息。先读取条件数量,再按该数量取主要错误,避免把 CONDITION 1 当作所有多条件场景的固定答案。会话变量只为教学观察使用,不是持久审计系统。
-- 在隔离测试库使用新的过程名;已有同名对象时不要直接覆盖
DELIMITER //
CREATE PROCEDURE demo_error_relay_28(IN p_reword BOOLEAN)
BEGIN
DECLARE v_count INT;
DECLARE v_state CHAR(5);
DECLARE v_errno INT;
DECLARE v_message TEXT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
-- 从堆叠诊断区读取触发处理器的原条件
GET STACKED DIAGNOSTICS v_count = NUMBER;
GET STACKED DIAGNOSTICS CONDITION v_count
v_state = RETURNED_SQLSTATE,
v_errno = MYSQL_ERRNO,
v_message = MESSAGE_TEXT;
-- 额外语句用于观察,可能影响当前诊断区但不替代原条件
SET @demo_original_state = v_state,
@demo_original_errno = v_errno,
@demo_original_message = v_message;
IF p_reword THEN
-- 只主动替换消息;不指定新 SQLSTATE 或错误号
RESIGNAL SET MESSAGE_TEXT = 'operation rejected; inspect server diagnostics';
END IF;
-- 不带任何参数,传递进入本处理器时的原条件
RESIGNAL;
END;
-- 受控测试输入:明确指定三项基线,不依赖未知业务表
SIGNAL SQLSTATE '45000'
SET MYSQL_ERRNO = 1644, MESSAGE_TEXT = 'demo input rejected';
END//
DELIMITER ;
DELIMITER 是 mysql 客户端命令,不是服务器 SQL。通过驱动创建过程时,应把完整 CREATE PROCEDURE 作为一个语句提交,不把 DELIMITER 发给服务器。需要相应建过程与调用权限;本文没有让读者替换现有生产过程。
用受控输入比较透传与消息改写
在专用连接分开调用两次。CALL 会按设计返回错误,如果客户端在错误后停止脚本,要在下一次交互中读取会话变量,或让测试代码先捕获异常再读取;不要误把“脚本停了”判断为没有保存诊断。
-- 第一组:预期向客户端传递完整原条件 CALL demo_error_relay_28(0); -- 捕获上面的预期异常后,在同一连接读取原条件观察值 SELECT @demo_original_state, @demo_original_errno, @demo_original_message;
-- 第二组:预期仅消息改为处理器指定文本 CALL demo_error_relay_28(1); -- 会话变量仍记录堆叠层读取的原条件,而不是改写后的消息 SELECT @demo_original_state, @demo_original_errno, @demo_original_message;
把客户端异常对象中的状态、数字码与消息分别保存。注意有的客户端会在消息外添加数据库前缀、过程名或格式化信息,不要把展示包装当作 MESSAGE_TEXT 自身。整个对照保持同一版本、同一过程和同一输入异常,仅改变模式参数。
把预期变化和实测数据分开
| 模式 | 客户端 SQLSTATE | 客户端错误号 | 消息的语义预期 |
|---|---|---|---|
| 0:裸 RESIGNAL | 45000 | 1644 | demo input rejected |
| 1:RESIGNAL SET MESSAGE_TEXT | 45000 | 1644 | operation rejected; inspect server diagnostics |
这张表来自示例中显式指定的条件和 RESIGNAL 的语义,不能作为已执行输出引用。读者应在自己的测试记录中填入实际值,并另记服务端版本及驱动信息。两组会话观察值都应保留原消息;第二组客户端收到的却是主动改写后的文本,这正是“原始记录”和“对外契约”的区别。

如果生产代码使用 RESIGNAL SQLSTATE ... 或 SET MYSQL_ERRNO,已经明确选择修改条件,不应继续宣称“完整保留原错”。要统一业务错误时,先独立保存底层诊断,并让调用端知道它接收的是新契约。
日志失败与事务责任仍要单独处理
上面的额外语句是简单 SET;替换成日志 INSERT 后,日志本身也可能失败。如果它抛出未处理的新异常,使后续 RESIGNAL 没有机会执行,原样透传设计就会被打断。日志与清理需要独立的失败策略,不能把示例夸大成“任何情况下都保留原错”。
若业务规定日志失败不得覆盖业务错误,可以在更小的嵌套块中专门处理日志异常,同时把日志失败发送到另一个受控观察渠道。这是主动取舍,不能静默吞掉所有清理失败后仍声称系统没有异常。
RESIGNAL 会自动回滚业务事务吗?
错误传递与事务归属是两件事。由调用者持有事务时,不要在通用处理器里无条件提交或回滚整个事务;应按明确的事务契约处理。本文示例没有开启事务,也没有业务写入。
能在普通语句位置直接 RESIGNAL 吗?
不能把它当成通用 SIGNAL;它要求活动的条件处理器上下文。没有原条件时,应重新设计异常产生的位置,而不是依赖 RESIGNAL 生成新错。
为什么示例没有使用 OUT 参数返回原错?
抛出异常后的 OUT/INOUT 传递另有规则,不宜把它当作一定可达的错误回传通道。应用应接收数据库异常;教学会话变量也不能跨连接读取,更不能在连接池中当作永久记录。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
132 收藏
-
数据库 · MySQL | 1小时前 | MySQL · InnoDB · 数据库运维 · mysql Threads 锁等待 data_locks performance_schema data_lock_waits INNODB_TRX 阻塞事务458 收藏
-
132 收藏
-
403 收藏
-
数据库 · MySQL | 1小时前 | MySQL · 事务 · 故障排查 · mysql transaction_read_only INNODB_TRX START TRANSACTION SET TRANSACTION102 收藏
-
124 收藏
-
231 收藏
-
335 收藏
-
488 收藏
-
483 收藏
-
315 收藏
-
166 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习