SqlServer存储过程与触发器实战:零基础构建高可用数据审计系统
|
我越来越觉得“SqlServer存储过程与触发器实战:零基础构建高可用数据审计系统”是错的。
文章配图,仅供参考 去年2月,我在十七个站里全量上线了那个被称作“审计金盾”的方案——主表加INSERT/UPDATE/DELETE三级触发器,每条变更写进AuditLog表,再用一个带事务标记的存储过程统一封装落库+校验+重试。林工当时拍着桌子说“这下连DBA睡着都能查到谁改了客户手机号”,李姐在晨会里直接把方案打印出来贴在白板上,标题叫《不可逆的审计铁律》。我原以为只要触发器里套上TRY...CATCH、存储过程开头加上SET XACT_ABORT ON、日志表建好非聚集索引,再配个SQL Agent每五分钟捞一次未归档记录——这事就稳了。结果上线第三天下午四点二十三分,客户投诉订单状态从“已发货”倒流回“待支付”,而AuditLog里根本没这条记录。不是延迟,不是漏查,是压根没生成。不是没触发,是触发器执行到一半,卡在了INSERT语句上——但返回码居然是0。我们仨蹲在测试库前用相同参数反复跑,它有时写,有时不写,有时连SET NOCOUNT ON都失效。 那会儿我还穿着那件洗得发灰的深蓝衬衫,袖口有咖啡渍,键盘右上角还粘着半片风干的柚子皮——去年春节前团建时带的,一直没撕。监控页面刷着红色告警,而SSMS里SELECT COUNT() FROM AuditLog WHERE [EventTime] > '2024-02-03 16:20' 的结果始终是0。李姐端着保温杯过来问:“是不是没走主键更新?”我说“是走的WHERE OrderID = @id”,她又问:“那你把触发器里那句INSERT拆出来单独跑试试。”我就拆了。跑了三遍。第一遍成功,第二遍报错“不能在触发器内显式调用INSERT EXEC”,第三遍……它居然返回了“命令已成功完成”,AuditLog里依然空空如也。可EXEC sp_who2里明明看见会话状态是sleeping,login_time却是两分钟前。 后来查到,问题不在触发器逻辑,而在某次紧急补丁中,DBA顺手给主表加了个WITH (SNAPSHOT)的隔离级别提示——但只加在ALTER INDEX语句里,没同步改应用连接字符串。于是触发器在快照隔离下读取自身修改前的状态,而INSERT INTO AuditLog又碰上了tempdb空间争抢,导致部分语句在write-ahead日志刷盘前被 silently discarded。没人知道,因为@@ERROR始终为0,XACT_STATE()返回1,PRINT语句在生产环境被注释掉了。那天我们查了十七个备份时间点的日志,翻出一张2022年11月的手写服务器巡检表,上面用红笔圈了“tempdb data file full → auto-grow disabled”,旁边批注是王工的字:“已联系存储团队,下周跟进”。下周变成了下个月,下个月变成了今年3月才真正扩容。 所以你说“零基础能建高可用审计系统”?哈。我见过新手把触发器里写RAISERROR('失败',16,1)后没加RETURN,结果后面继续执行INSERT INTO AuditLog,造成重复日志;见过同事为省事把@OldValue和@NewValue全塞进NVARCHAR(MAX),结果单条审计记录超8000字节,整个批量UPDATE崩掉;还见过用GETDATE()当事件时间戳,结果三台数据库服务器之间NTP漂移27秒,审计链直接断成三截。这些不是边缘case——它们是第一批上线用户踩出来的坑。我们最后把触发器全砍了,改成应用层EF Core拦截器+数据库端扩展事件(XEvents)捕获statement_completed,再用Logstash拉到Elasticsearch。不是更可靠,是更容易定位哪一层出了问题。毕竟你总不能让运维去教业务开发看执行计划里的Nested Loops vs Hash Match区别吧。 对了,那天凌晨两点我删掉第十七个失败的JOB步骤时,电脑右下角弹出Windows Update提示:KB5034441补丁待安装,更新说明里有一行小字:“修正 SQL Server 在 READ_COMMITTED_SNAPSHOT = ON 场景下,触发器内 INSERT 操作偶发静默丢失的问题”。发布时间是2024年1月29日。比我们上线早四天。 所以现在我看见“零基础”这三个字就想笑。零基础的人不该碰触发器——他们连sp_who2和sp_who的区别都说不清;也不该碰存储过程审计——连SET ANSI_NULLS ON要不要保持一致都不知道。真正的高可用不是堆功能,是留退路。我们后来给每个关键表加了影子列(LastModifiedBy、LastModifiedOn),靠应用代码强制更新,数据库只负责拦住NULL值。不是优雅,是认怂。认怂之后,反而没人投诉审计漏数了。这事我也可能就运气好——刚好王工那张手写表没丢,刚好补丁发布日期我们能查到,刚好李姐坚持要复现三遍才拉DBA开会。别的组,未必有这运气。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

