SQL Server触发器中TRY CATCH仅捕获可恢复运行时错误(如除零、类型转换失败),无法捕获编译期错误或终止性错误;MySQL触发器不支持错误捕获,出错即回滚;日志记录须前置到存储过程或应用层,并确保对象存在、避免隐式转换、使用独立带TRY CATCH的日志过程且禁用XACT_ABORT。

SQL Server 触发器里 TRY CATCH 能捕获哪些错误
只能捕获可恢复的运行时错误,比如除零、类型转换失败、字符串截断;无法捕获编译期错误(列名拼错、表不存在)或终止性错误(外键冲突、唯一约束违反)。你看到触发器“静默失败”,大概率是遇到了后者——ERROR_NUMBER() 在这种情况下根本不会被设置,TRY CATCH 块直接跳过。
MySQL 触发器根本不能捕获任何运行时错误
MySQL 触发器不支持 DECLARE HANDLER,也不允许 TRY CATCH。一旦出错(如 ERROR 1422、ERROR 1048),整个语句立刻回滚,触发器中断,连日志表都写不进去。别在触发器里做校验、查重、跨表更新——这些逻辑必须前置到存储过程或应用层。
记录上下文信息必须绕开触发器自身事务
- 日志表字段要极简:
id(IDENTITY)、error_time(DATETIME2)、error_number(INT)、error_message(NVARCHAR(4000))、proc_name(NVARCHAR(128)) - 插入前必须检查对象存在:
IF OBJECT_ID('dbo.error_log') IS NOT NULL - 避免用
VALUES直接插,改用INSERT INTO ... SELECT防止隐式转换失败 - 最稳妥的方式是把日志逻辑抽成独立存储过程(如
usp_log_error),并在其内部再套一层TRY CATCH,但结尾必须加SET XACT_ABORT OFF,且绝不执行COMMIT或ROLLBACK
客户端信息不能靠 APP_NAME() 自动识别
APP_NAME() 只返回连接字符串中显式声明的 Application Name 参数值。Java JDBC 必须带 applicationName=xxx,.NET 连接字符串必须含 Application Name=xxx;SSMS 默认值是 Microsoft SQL Server Management Studio,连接池或代理可能污染该值。想拿到真实来源,得从应用层源头控制,而不是在触发器里“猜”。
真正能记下的上下文,永远受限于错误发生的那一刻——编译期错没机会进 CATCH,MySQL 触发器错根本没机会写日志,而 APP_NAME() 不设就是空。别指望触发器兜底,它只适合做确定性操作。

















