使用SqlCommand执行时,可能导致链接服务器查询失败的原因?

问题描述 投票:0回答:1

背景

我的C#应用​​程序是Windows服务,允许用户配置SQL查询,这些查询涉及链接的服务器,以类似于ETL(提取转换负载)应用程序来移动数据。这些查询已经直接在SSMS中进行了测试,并且可以正常工作。

下面是一个示例查询,它将数据从本地服务器上的LocalDB数据库插入到RemoteServer上的RemoteDB数据库。随其列出了RemoteServer配置:

EXEC master.dbo.sp_addlinkedserver @server = N'RemoteServer', @srvproduct=N'SQL Server'

INSERT INTO RemoteServer.RemoteDB.dbo.tst_Address (Address, FirstName, LastName, DateOfBirth)
    SELECT t1.Address, t1.FirstName, t1.LastName, t1.DateOfBirth  
    FROM LocalDB.dbo.tst_Address t1 
    LEFT JOIN RemoteServer.RemoteDB.dbo.tst_Address t2 ON t2.Address = t1.Address
    WHERE t2.Address IS NULL 

问题

直接从SSMS执行时没有问题,但是当使用SqlCommand.ExecuteNonQuery()从c#应用程序执行时,我发现各种错误,具体取决于我从哪台计算机上运行该应用程序。例如,我手头的一个例外是

System.Data.SqlClient.SqlException(0x80131904):执行超时已过期。在操作完成之前超时时间已过,或者服务器没有响应。

System.ComponentModel.Win32Exception(0x80004005):等待操作超时

另一台计算机给出:

命名管道提供者:无法打开与SQL Server [5]的连接。链接服务器“ RemoteServer”的OLE DB访问接口“ SQLNCLI11”返回消息“登录超时已过期”。链接服务器“ RemoteServer”的OLE DB提供程序“ SQLNCLI11”返回消息“建立与SQL Server的连接时发生了与网络相关或特定于实例的错误。找不到或无法访问服务器。请检查实例名称是否正确以及是否SQL Server配置为允许远程连接。有关更多信息,请参见SQL Server联机丛书。“]

已启用命名管道,并且超时发生在大约5-10秒内。

该登录名是Windows用户,在两台服务器上均具有sysadmin角色,但是我也尝试通过sp_addlinkedsrvlogin设置SQL用户,但对抛出的异常没有影响。

我无法看到为什么应该有任何区别,因为我期望SqlCommand将SQL发送到SQL Server服务进行处理。我想念什么?

c# sql sql-server linked-server
1个回答
1
投票

所以看来这里有两个问题:

  1. SSMS中执行的查询的行为与通过SqlCommand在.NET中的查询有所不同,并且
  2. MSDTC需要更多的知识,而不仅仅是在方框中打勾

SSMS与.NET

当我通过SSMS进行测试时,我试图尽可能地复制.NET方法。

。NET代码

var queryText = @"INSERT INTO RemoteServer.RemoteDB.dbo.tst_Address (Address, FirstName, LastName, DateOfBirth)
    SELECT t1.Address, t1.FirstName, t1.LastName, t1.DateOfBirth  
    FROM LocalDB.dbo.tst_Address t1 
    LEFT JOIN RemoteServer.RemoteDB.dbo.tst_Address t2 ON t2.Address = t1.Address
    WHERE t2.Address IS NULL"
using (var trans = cxn.BeginTransaction())
{
    try
    {
        var cmd = this.BuildSqlCommand(queryText, parameters);
        cmd.ExecuteNonQuery();
        trans.Commit();
    }
    catch (Exception ex)
    {
        logger.Error(ex);
        throw;
    }
}

SSMS查询

begin tran
begin try

INSERT INTO RemoteServer.RemoteDB.dbo.tst_Address (Address, FirstName, LastName, DateOfBirth)
    SELECT t1.Address, t1.FirstName, t1.LastName, t1.DateOfBirth  
    FROM LocalDB.dbo.tst_Address t1 
    LEFT JOIN RemoteServer.RemoteDB.dbo.tst_Address t2 ON t2.Address = t1.Address
    WHERE t2.Address IS NULL
commit

end try
begin catch

    SELECT  
        ERROR_NUMBER() AS ErrorNumber  
        ,ERROR_SEVERITY() AS ErrorSeverity  
        ,ERROR_STATE() AS ErrorState  
        ,ERROR_PROCEDURE() AS ErrorProcedure  
        ,ERROR_LINE() AS ErrorLine  
        ,ERROR_MESSAGE() AS ErrorMessage;  
    if @@TRANCOUNT > 0
        rollback

end catch

SSMS的缺点是,默认情况下不需要分发查询,并且不包含DTC,除非使用begin distributed tran明确告知了该查询。一旦添加了分布式关键字,SSMS也会因与.NET类似的错误而失败。

SQL Server connection settings

DTC配置

在Component Services(从命令行dcomcnfg)中找到了记录充分的复选框,典型设置如下所示。

MSDTC Local Settings

让我感到震惊的是,Windows防火墙规则虽然已存在,但默认情况下是禁用的。尝试访问RemoteServer的两台计算机之间的潜在差异是,一台计算机已禁用防火墙,因此不受出站规则的阻止,但两者均被RemoteServer上禁用的入站规则的阻止。这是出站规则

Outbound Firewall Rules

和现在显示的入站规则已启用。

Inbound Firewall Rules

© www.soinside.com 2019 - 2024. All rights reserved.