0

我们有两个直接相关的问题,可以简化为一段非常简单的代码。假设机器 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 协议,我会在其中设计一个心跳,以便在足够多的秒数内没有响应 = 断定,退出,清理。我想要一种实现相同想法的方法,即将安静的挂起变成嘈杂的崩溃,以便清理代码可以清理它。

4

2 回答 2

1

这已经存在。它被称为保持活动状态。

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

SQL Server 将使用 KeepAlive 数据包探测连接,如果客户端不再存在,应该会在几分钟内快速检测到。

但是,这对您没有帮助 - 您希望客户端发送 keepalives 以确保服务器仍在运行。

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

于 2013-05-02T22:41:51.113 回答
0

这是另一个建议。

在 SQL Server 上实现一个名为CheckConnection(@spid int)的过程,它将以某种方式报告连接的状态。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 将被重用)。

于 2013-05-03T09:27:29.283 回答