mysql如何捕捉SQL执行异常_mysql异常日志记录

来源:这里教程网 时间:2026-02-28 20:49:33 作者:

MySQL客户端执行SQL时如何捕获异常

MySQL本身不提供类似编程语言的

try...catch
机制,异常捕获必须依赖客户端(如Python、Java、PHP)或存储过程内的错误处理逻辑。直接在命令行或
mysql
客户端敲SQL时,异常只显示在终端,不会自动记录到日志文件。

常见现象:执行

INSERT INTO t VALUES (1/0)
会报
ERROR 1365 (22012): Division by 0
,但这条错误不会进任何MySQL服务端日志——除非你主动开启相关日志。

命令行下用
mysql -e "SQL"
执行时,可通过
$?
检查退出码(非零即失败)
在存储过程中,可用
DECLARE ... HANDLER
捕获特定SQLSTATE或错误码,例如
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000'
应用层务必检查执行返回值或异常对象,不能只看SQL是否“看起来跑完了”

开启MySQL通用查询日志(含错误语句)

通用日志(

general_log
)会记录所有到达MySQL服务器的语句(包括语法错误的),但它不区分成功/失败,且默认关闭,开启后对性能有明显影响,仅建议临时排障。

启用方式(需有SUPER权限):

SET GLOBAL general_log = ON;
SET GLOBAL log_output = 'file'; -- 或 'table',写入mysql.general_log表
SET GLOBAL general_log_file = '/var/log/mysql/general.log';

注意:

general_log
记录的是“收到的原始SQL”,不是执行结果;语法错误的SQL也会被记入,但执行阶段抛出的运行时错误(如唯一键冲突)不会额外标注为“异常”,需人工对照时间戳和后续返回信息判断。

日志路径需MySQL进程有写权限,否则启动失败且无提示 开启后日志体积增长极快,切勿长期开启
log_output = 'table'
时,查
SELECT * FROM mysql.general_log ORDER BY event_time DESC LIMIT 10
可快速回溯

错误日志(error log)里能抓到哪些SQL异常

MySQL的错误日志(由

log_error
配置项指定)**不记录普通SQL执行失败**,它只记录服务启动、崩溃、连接异常、权限拒绝、表损坏等服务端级问题。像
INSERT ... ON DUPLICATE KEY UPDATE
中的主键冲突、
UPDATE
影响0行、甚至
Deadlock found
这类事务错误,默认也不会写入
error log

真正能进错误日志的SQL相关异常极少,典型如:

解析阶段失败:SQL语法严重错误导致mysqld无法初始化语句树(罕见) 权限类拒绝:
Access denied for user ... to database ...
磁盘满导致
Failed to write to binlog
进而中断SQL执行

所以别指望靠

error log
审计业务SQL失败原因——它不是为这个设计的。

真正可靠的SQL异常追踪方案

生产环境要稳定捕获SQL异常,必须组合使用客户端日志 + 慢查询日志 + 性能模式(Performance Schema)。

slow_query_log
配合
long_query_time = 0
可记录所有SQL(含失败语句),但需注意:它只记录执行时间超限的语句,而很多异常(如语法错、权限错)根本没走到执行阶段,就不会被记录。

更实用的是启用Performance Schema中的语句事件监控:

UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_history_long';
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME = 'statement/sql/%';

之后查

performance_schema.events_statements_history_long
,字段
SQL_TEXT
ERROR_CODE
ERROR_MESSAGE
会明确标出失败语句及其错误详情。这是目前MySQL原生最接近“SQL异常日志”的能力。

该功能默认可能关闭,且消耗一定内存,需评估实例负载
ERROR_CODE
为0表示成功,非0即失败(如1062是重复键,1213是死锁)
历史记录滚动覆盖,需及时采集,不能依赖它长期存档

复杂点在于:没有单一开关能“打开SQL异常日志”。你得根据场景选工具——调试用

general_log
,运维监控靠
performance_schema
,应用层兜底靠客户端异常捕获。漏掉任意一环,异常就悄无声息地消失了。

相关推荐