2013-05-02 60 views
0

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

你可能会说“让你的网络可靠”。我也是如此。我需要证明这并非首先在客户相信之前明确地捕捉到问题。

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

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协议,我会设计一个心跳进入它,以便没有足够秒数的响应=结束死亡,纾困,清理。我想要一种方法来实现相同的想法,那就是将安静的挂起变成嘈杂的崩溃,以便清理代码可以清理它。

回答

1

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

的信息请参见以下内容:

SQL Server将探头激活数据包的连接,并应在几分钟之内快速检测,如果客户端已不存在。

但是,这并不能帮助你 - 你希望客户端发送Keepalive以确保服务器仍在运行。

似乎没有支持这样做的方式。如果你想在你的客户端套接字上启用TCP KeepAlive,你将不得不使用Reflection或不安全的代码来定位实际的TCP套接字并使用WSAIoctl来启用Keepalive。在我的其他答案中给出了一个更好的解决方案。

+0

那么这就是最好的答案。现在,如何在客户端连接上设置Keepalive将完成它。 – Joshua 2013-05-02 23:34:47

+0

@Joshua,事实证明,它只能由服务器发送,而不是客户端发送。 – Ben 2013-05-03 09:09:56

+0

我接受这个答案是答案的一半,另一半不存在,任何使它存在的方式都会涉及很多骇客。 – Joshua 2013-05-04 22:13:18

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是否仍处于活动状态,并且仍然具有相同的客户端。 (检查客户端是相同的,因为一旦关闭SPID将被重新使用)。

+0

不幸的是,应用程序的runas用户不能使用master.dob.sysprocesses(它只能看到一个仅包含它自己的模型)。 – Joshua 2013-05-03 15:15:36

+0

@joshua,把这个过程放在主人面前,然后授予公众。然后它会工作。 (当你这样做时,确保你是系统管理员)。 – Ben 2013-05-03 16:59:09

+0

不会让我在升级过程中不得不要求sa权限,这是我们在太多服务调用后没有养成的习惯 – Joshua 2013-05-03 17:19:46

相关问题