SQL Server存储过程与触发器实战:构建高可用数据审计系统
|
去年10月份,我们团队接了个金融行业的项目——要给某银行核心系统加数据审计模块,甲方要求所有资金类表的操作必须记录变更前后数据,且审计日志要独立存储,不能影响主业务性能。当时摆在我们面前的有两条路:要么用应用层记录,要么用数据库原生能力。前者需要改所有资金接口,周期得按年算;后者——我盯着SQL Server的存储过程和触发器文档,突然觉得这事儿有戏。 存储过程在审计里的核心价值,是能把复杂的变更逻辑封装成原子操作。比如用户余额变更,传统做法是在每个UPDATE语句前后各查一次表,再拼日志——但触发器能直接在UPDATE事件里捕获OLD/NEW值,用INSERT INTO审计表...SELECT @old_balance, @new_balance...这种写法,代码量直接砍掉70%。我们测试时发现,用存储过程批量插入1000条审计日志,耗时比应用层循环调用API快12倍——这还没算网络延迟的损耗。 但真正让我拍板用触发器的,是个失败案例——之前某项目用应用层记录审计,结果有次部署新版本时,审计日志的存储过程没同步更新,导致三个月的数据变更没被记录。触发器的好处是它和表绑定,只要表结构不变,触发器逻辑就跟着走,哪怕应用层代码全换了,审计也不会丢。去年10月我们上线第一版时,特意在触发器里加了版本号字段,每次表结构变更就自动更新触发器版本——到现在半年了,审计数据一条没漏。 不过触发器也不是银弹——我们踩过个大坑。有次审计表用了TEXT类型存变更详情,结果触发器里拼接字符串时,超过8000字节就截断了。后来改成NVARCHAR(MAX),又在存储过程里加了异常处理:BEGIN TRY...INSERT...END TRY BEGIN CATCH...ROLLBACK...END CATCH——这招救了我们三次,有次审计表空间满了,触发器自动回滚了主表操作,避免数据不一致。这种数据库原生的错误处理,应用层很难做到这么及时。 说到新技术,我必须夸夸SQL Server 2019的增强功能——比如系统版本化临时表,能让我们在触发器里先存变更到临时表,再批量插入审计表,减少IO压力。还有JSON支持,现在审计详情直接存JSON格式,比以前用分隔符拼接的字符串好查多了。去年10月我们测试时,用JSON_QUERY提取特定字段的查询速度,比字符串分割快5倍——这在高并发场景下太关键了。 但最让我惊喜的,是触发器和存储过程的组合能实现“被动审计”到“主动防御”的升级。比如我们在用户余额变更触发器里加了条件判断:IF @new_balance - @old_balance > 10000 THEN INSERT INTO风控表...——这相当于把风控规则下沉到数据库层,哪怕应用层没做校验,数据库也能拦住大额异常操作。去年12月,这功能真拦下了一起内部测试的越权操作——测试人员故意没走风控接口,结果触发器直接拒绝变更并报警。
文章配图,仅供参考 当然,这套方案也有局限——触发器会增加表操作的延迟,我们测过,单条UPDATE带触发器比不带慢3-5ms。但在金融场景里,这3ms换来的是数据不可篡改的审计能力,值!不过要是遇到每秒万级的操作,可能得考虑用Service Broker把审计操作异步化——我们正在研究这个,下月应该能出测试版。下一步我打算把这套方案开源到GitHub,但得先解决个问题——不同版本的SQL Server语法有差异,比如2016不支持JSON,2019才支持系统版本化临时表。可能得写个版本检测脚本,自动生成适配不同版本的触发器代码。要是你有类似场景的需求,或者遇到过更奇葩的审计需求,欢迎来聊聊——说不定我们能一起把这套方案磨得更锋利。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

