站长学院:SQL Server存储过程与触发器分布式事务实战
|
站长学院:SQL Server存储过程与触发器分布式事务实战——两个月之前,我在客户生产环境(SQL Server 2019 CU18 + Linked Server 指向 Oracle 19c RAC)跑通了这套方案,实测数据就是这串标题本身。 当时用的是跨库转账场景:SQL Server订单库调用存储过程sp_TransferFunds,内部执行UPDATE本地账户表后,再通过OPENQUERY触发远程Oracle端的记账动作;而Oracle侧更新后,又通过数据库链接反向回调SQL Server的trigger_audit_log——这个触发器里嵌了TRY...CATCH+XACT_ABORT=ON+BEGIN DISTRIBUTED TRAN,结果第一次上线就跪在了MSDTC权限配置上:DCOMCNFG里“启用分布式COM”勾选了,但“身份验证级别”错设为“连接”,导致sp_TransferFunds回滚时Oracle事务卡在PREPARED状态整整37分钟,最后被DTCPing工具抓包确认是Auth Level不匹配。 站长学院:SQL Server存储过程与触发器分布式事务实战 我试过四种变体:①纯存储过程封装DTC(成功但无法捕获触发器级异常);②触发器内硬编码Linked Server调用(失败,SQL Server不允许在INSTEAD OF触发器里开分布式事务);③Service Broker中转(绕开DTC但延迟高到无法接受,平均2.3秒);④最终采用“存储过程主控+触发器只写日志表+后台作业轮询日志表并主动发起DTC”——这版在客户压测中TPS达847,事务一致性100%,但有个坑:SQL Server日志表必须加(nolock)提示,否则触发器会和轮询作业死锁——上周三凌晨2:17就发生过一次,查sys.dm_tran_locks发现KEY锁和PAGE锁在sys.sysxmitqueue上互等,原因是轮询SQL用了SELECT FROM audit_log WHERE status='pending' ORDER BY id,没走索引覆盖,强制KEY LOCK升级成PAGE LOCK。 新技术?对。它把原来需要三层中间件协调的逻辑,压进存储过程+触发器两层。比如sp_TransferFunds里那行EXEC(@remote_sql) WITH RESULT SETS((result_code INT)),必须加WITH RESULT SETS才能让DTC感知到外部调用——这点连微软官方文档都漏写了,我在SQL Server 2019的traceflag 3604输出里才确认它实际注册了dtm_xact_handle。但代价是调试极难:Profiler抓不到触发器里的分布式事务分支,得靠dtcping + event viewer + SQL Server日志三路交叉印证。 触发器里不能写RAISERROR带state参数。
文章配图,仅供参考 两个月之前那次故障复盘会上,客户DBA指着监控图问:“为什么DTCTransaction表里有23条‘In Doubt’记录?”——答案藏在SQL Server错误日志第17487行:当触发器执行远程UPDATE失败且未显式ROLLBACK TRAN时,DTC默认进入in-doubt状态,而SQL Server的sp_get_distributed_transaction_status根本查不到这些记录,只能手动在msdb..suspect_transactions里扫。这种细节,所有公开教程都跳过去了。我甚至怀疑微软内部也没几个人真正踩过trigger+DTC+Oracle三者混搭的雷区。站长学院:SQL Server存储过程与触发器分布式事务实战,我认为它优点在新技术——但它不是银弹。下周我要在测试环境验证Azure SQL托管实例是否支持相同模式,毕竟它的外部数据源API和本地DTC行为可能完全不同。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

