"MS DTC has cancelled the distributed transaction" SQLCLR 存储过程中的错误
"MS DTC has cancelled the distributed transaction" error in SQLCLR stored procedure
我需要将一些代码从旧项目移到新项目。旧项目使用带存储过程的 DLL(32 位版本),但我需要在 64 位 SQL 服务器上使用此 DLL,因此我需要重写这些程序。
我正在为 SQL Server 2008 编写带有存储过程的 dll。在 Management Studio 中,我加载程序集,然后使用以下方法创建过程:
CREATE PROCEDURE ...
AS EXTERNAL NAME
旧的 DLL 程序只是使用到远程 SQL 服务器的新连接到其上的 运行 存储过程和 return 结果。
所以在我的过程中,我创建了一个 SqlConnection
到远程服务器,并在远程服务器上创建了 运行 存储过程:
using (SqlConnection connection = new SqlConnection(String.Format("User ID={0};Password={1};Persist Security Info=True;Initial Catalog={2};Data Source={3}", Login, Password, DBName, ServerName)))
{
connection.Open();
SqlCommand command = new SqlCommand("Exec ProcName", connection);
SqlDataReader reader = command.ExecuteReader();
SqlContext.Pipe.Send(reader);
}
如果我 运行 在 SSMS 中使用这个程序,它就可以工作。但是在旧项目中它会引发错误:
The Microsoft Distributed Transaction Coordinator (MS DTC) has cancelled the distributed transaction.
MSDTC 服务 运行s,我设置了所有安全参数。如何解决?也许还有其他方法可以 运行 远程存储过程(链接服务器),但我需要保存旧项目功能。
这里有几件事情不太对劲:
你为什么要重写任何东西?如果您有代码,最坏的情况就是为新架构重新编译。
你一开始为什么要做什么?代码应该针对 "Any CPU"(在 "Project Properties" 的 "SQLCLR Build" 选项卡中的 "Platform target" 下)编译,而不是专门针对 32 位或 64 位。如果它已经在 "Any CPU" 下编译,则无事可做。在开始任何重新编译 and/or 重写之前,您是否在新系统上进行了测试?
不要使用 String.Format
创建连接字符串。相反,使用 SqlConnectionStringBuilder:
SqlConnectionStringBuilder _ConnectionStringBuilder =
new SqlConnectionStringBuilder();
_ConnectionStringBuilder.DataSource = ServerName;
_ConnectionStringBuilder.InitialCatalog = DBName;
_ConnectionStringBuilder.UserID = Login;
_ConnectionStringBuilder.Password = Password;
除非你别无选择,必须使用这个选项,否则不要指定Persist Security Info=True;
而不是使用 new SqlCommand()
,创建 SqlCommand
使用:
using(SqlCommand command = connection.CreateCommand())
{
command.CommandText = "Exec ProcName";
}
一定要指定 command.CommandType = CommandType.StoredProcedure;
以便它执行实际的 RPC 调用而不是临时查询。这将要求您从 "EXEC ProcName" 的当前 CommandText
中删除 "EXEC" 的文本;您只能指定 [[DatabaseName.]SchemaName.]ProcName
.
一个SqlDataReader
是一个一次性对象,就像SqlConnection
和SqlCommand
一样,所以SqlDataReader reader = command.ExecuteReader()
应该被包裹在一个[=23中=]构造.
更正上述项目后,您应该能够通过简单地设置 SqlConnectionStringBuilder 的以下 属性 来修复错误:_ConnectionStringBuilder.Enlist = false
.
有关使用 SQLCLR 的更多详细信息和示例,请参阅我在 SQL Server Central 上就此主题撰写的系列文章:Stairway to SQLCLR(免费注册需要阅读该网站上的内容)。
我需要将一些代码从旧项目移到新项目。旧项目使用带存储过程的 DLL(32 位版本),但我需要在 64 位 SQL 服务器上使用此 DLL,因此我需要重写这些程序。
我正在为 SQL Server 2008 编写带有存储过程的 dll。在 Management Studio 中,我加载程序集,然后使用以下方法创建过程:
CREATE PROCEDURE ...
AS EXTERNAL NAME
旧的 DLL 程序只是使用到远程 SQL 服务器的新连接到其上的 运行 存储过程和 return 结果。
所以在我的过程中,我创建了一个 SqlConnection
到远程服务器,并在远程服务器上创建了 运行 存储过程:
using (SqlConnection connection = new SqlConnection(String.Format("User ID={0};Password={1};Persist Security Info=True;Initial Catalog={2};Data Source={3}", Login, Password, DBName, ServerName)))
{
connection.Open();
SqlCommand command = new SqlCommand("Exec ProcName", connection);
SqlDataReader reader = command.ExecuteReader();
SqlContext.Pipe.Send(reader);
}
如果我 运行 在 SSMS 中使用这个程序,它就可以工作。但是在旧项目中它会引发错误:
The Microsoft Distributed Transaction Coordinator (MS DTC) has cancelled the distributed transaction.
MSDTC 服务 运行s,我设置了所有安全参数。如何解决?也许还有其他方法可以 运行 远程存储过程(链接服务器),但我需要保存旧项目功能。
这里有几件事情不太对劲:
你为什么要重写任何东西?如果您有代码,最坏的情况就是为新架构重新编译。
你一开始为什么要做什么?代码应该针对 "Any CPU"(在 "Project Properties" 的 "SQLCLR Build" 选项卡中的 "Platform target" 下)编译,而不是专门针对 32 位或 64 位。如果它已经在 "Any CPU" 下编译,则无事可做。在开始任何重新编译 and/or 重写之前,您是否在新系统上进行了测试?
不要使用
String.Format
创建连接字符串。相反,使用 SqlConnectionStringBuilder:SqlConnectionStringBuilder _ConnectionStringBuilder = new SqlConnectionStringBuilder(); _ConnectionStringBuilder.DataSource = ServerName; _ConnectionStringBuilder.InitialCatalog = DBName; _ConnectionStringBuilder.UserID = Login; _ConnectionStringBuilder.Password = Password;
除非你别无选择,必须使用这个选项,否则不要指定
Persist Security Info=True;
而不是使用
new SqlCommand()
,创建SqlCommand
使用:using(SqlCommand command = connection.CreateCommand()) { command.CommandText = "Exec ProcName"; }
一定要指定
command.CommandType = CommandType.StoredProcedure;
以便它执行实际的 RPC 调用而不是临时查询。这将要求您从 "EXEC ProcName" 的当前CommandText
中删除 "EXEC" 的文本;您只能指定[[DatabaseName.]SchemaName.]ProcName
.一个
SqlDataReader
是一个一次性对象,就像SqlConnection
和SqlCommand
一样,所以SqlDataReader reader = command.ExecuteReader()
应该被包裹在一个[=23中=]构造.
更正上述项目后,您应该能够通过简单地设置 SqlConnectionStringBuilder 的以下 属性 来修复错误:_ConnectionStringBuilder.Enlist = false
.
有关使用 SQLCLR 的更多详细信息和示例,请参阅我在 SQL Server Central 上就此主题撰写的系列文章:Stairway to SQLCLR(免费注册需要阅读该网站上的内容)。