begin distributed transaction 不会报错但常静默降级为本地事务,因ms dtc配置、rpc设置、链接服务器属性或sql写法任一缺失;跨实例操作须用四部分命名或openquery,禁用opendatasource/openrowset。

BEGIN DISTRIBUTED TRANSACTION 在存储过程中几乎从不“直接生效”——它只是个开关,背后所有配置、写法、权限缺一不可,否则事务静默降级为本地事务,远程操作照常提交,数据已不一致。
为什么 BEGIN DISTRIBUTED TRANSACTION 总是不报错却没效果
SQL Server 不会在条件缺失时抛错,而是自动放弃升级,继续走本地事务流程。常见静默降级原因包括:
-
sp_configure 'remote proc trans', 1未启用 → 远程语句不会触发事务升级 - 链接服务器未开启
rpc out→EXEC [srv_link].db.dbo.sp_name被拒绝或绕过事务上下文 - MS DTC 服务未运行,或防火墙拦了端口 135 + 动态 RPC 端口 → 升级请求直接失败
- 组件服务中 MSDTC 安全配置漏勾“允许入站”“允许出站”“允许远程客户端” → 事务降级为本地,无提示
- 未设置
SET XACT_ABORT ON→ 错误只回滚单条语句,DTC 不介入,后续仍会COMMIT本地部分
跨实例写操作必须用四部分命名,不能靠远程存储过程
即使 MSDTC 全部配好,EXEC [srv_link].db.dbo.sp_name 也**不会**让远程 SP 内部的 BEGIN TRAN 参与两阶段提交。SQL Server 把它当黑盒原子调用,只管返回码(@@ERROR),不协调其内部事务。
真正能纳入分布式事务的,只有你本地发起的跨库语句:
INSERT INTO [srv_link].RemoteDB.dbo.Table1UPDATE [srv_link].RemoteDB.dbo.Table2 SET col = 1 WHERE id = 1- 或用
OPENQUERY([srv_link], 'INSERT INTO ...')封装成单条语句(注意:该语句本身必须在BEGIN DISTRIBUTED TRANSACTION块内)
绝对禁用 OPENDATASOURCE 和 OPENROWSET —— 它们彻底脱离事务上下文,永远无法加入分布式事务。
MySQL 跨实例 XA 事务不能靠 XA START 自动协调
MySQL 的 XA START 'xid' 只支持单实例内多个连接协作,**不支持跨 MySQL 实例自动 prepare/commit**。所谓“跨库 XA”,本质是应用层用 Atomikos、Seata 等协调器,串行驱动各节点执行本地 XA 流程。
常见错误:ERROR 1399 (XAE04): XAER_RMFAIL —— 多因第二阶段时某个节点已断开,或未真正完成 XA PREPARE;xid 必须全局唯一、长度 ≤130。
最容易被忽略的一点:分布式事务不是“写了 BEGIN DISTRIBUTED TRANSACTION 就完事”,而是要逐项验证 MSDTC 服务状态、RPC 配置、链接服务器属性、SQL 语句结构、甚至远程数据库是否真的允许被写入——任一环节断裂,事务就已悄悄失效,且不给你任何警告。











