由于网络丢失,SqlServer楔入连接

时间:2013-05-02 20:44:13

标签: .net sql-server tcp

我们有两个直接相关的问题,可以简化为一段非常简单的代码。 假设机器1托管应用程序,机器2托管数据库,通过集线器通过以太网连接。 我们将通过从集线器上拔下网络电缆来模拟网络问题。

您可能会说“让您的网络可靠”。我也是如此。在客户相信之前,我需要通过明确捕捉问题来证明它不是第一个。

我们无法通过超时解决此问题,因为我们有一些/非常/长时间运行的查询和非查询。是的,其中一些确实需要一个小时或更长时间,并且用户不会忍受盯着冻结的会话足够长的时间来获得真正的错误。他们反而杀了它。

using System.Data;
using System.Data.SqlClient;

public class test {
    public static void hang1()
    {
        using SqlConnection oConnection = applib.getConnection() // returns an open connectin
        {
            using SqlCommand oCmd = new SqlCommand("WAITFOR DELAY 00:01:00", oConnection)
                oCmd.ExecuteNonQuery(); // unplug cable between hub and database server when in this call and this call never returns
        }
     }

     public static void hang2()
     {
            using SqlCommand oTCmd = new SqlCommand("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE", oConnection)
                oCmd.ExecuteNonQuery();

            using oTransaction = new SqlClient.SqlTransaction
            {

            using SqlCommand oCmd = new SqlCommand("SELECT max(id) FORM Table1")
            {
               oCmd.Transaction = oTransaction;
               oCmd.ExecuteScaler();
               System.Threading.Thread.Sleep(60 * 1000);
               // Disconnect the cable between the hub and the application server here
               // Now table Table1 is locked and will remain locked until the transaction
               // is manually killed from the database server.
               oCmd.ExecuteScaler();
            }
            }
      }
 }

我们正在寻找一种解决方案来检测交易是否被卡住而无需在其上设置超时。如果我正在设计我自己的TCP / IP协议,我会在其中设计一个心跳,以便在足够的秒数内没有响应=结束死亡,纾困,清理。我想要一种方法来实现相同的想法,即将安静的挂起变成嘈杂的崩溃,以便清理代码可以清理它。

2 个答案:

答案 0 :(得分:1)

这已经存在。它被称为保持活着。

有关信息,请参阅以下内容:

SQL Server将探测与KeepAlive数据包的连接,并且应该在几分钟内快速检测到客户端是否不再存在。

然而,这对您没有帮助 - 您希望客户端发送keepalive以确保服务器仍然没有用。

似乎没有支持这种做法。如果要在客户端套接字上启用TCP KeepAlives,则必须使用Reflection或不安全的代码来定位实际的TCP套接字并使用WSAIoctl来启用keepalive。在我的另一个答案中给出了一个可能更好的解决方案。

答案 1 :(得分:0)

这是另一个建议。

在SQL Server上实现一个名为CheckConnection(@spid int)的proc,它将以某种方式报告连接的状态。您可以从master.sys.sysprocesses或更新的信息架构视图中找到此信息。

这样的事情:

create proc CheckConnection(@spidToCheck int)
as
begin

    select 
        spcheck.spid, spcheck.blocked, 
        spcheck.lastwaittype, 
        (select name from master.dbo.sysdatabases sd where sd.dbid = spcheck.dbid) as database_name,
        spcheck.physical_io, 
        spcheck.memusage,
        spcheck.login_time,
        spcheck.last_batch, 
        spcheck.open_tran,
        spcheck.status,
        case 
        when spcheck.spid = spcurrent.spid
        then 'Same Connection'
        when 
        spcheck.net_library = spcurrent.net_library
        and spcheck.net_address = spcurrent.net_address
        and spcheck.sid = spcurrent.sid
        and spcheck.hostprocess = spcurrent.hostprocess
        then 'Same Client'
        else 'Different Client'
        end as client_status
    from master.dbo.sysprocesses spcheck
    inner join master.dbo.sysprocesses spcurrent
    on spcheck.spid = @spidToCheck and spcurrent.spid = @@spid



end

在执行长时间运行的进程之前,您可以通过执行connection.ExecuteScalar("select @@SPID as SPID");找到连接对象的SPID。然后,您可以使用单独的连接每隔几分钟监控SPID是否仍然有效且仍然具有相同的客户端。 (检查客户端是否相同是必要的,因为SPID将在关闭后重复使用。)