.net 在IP更改后重新连接丢弃的SqlConnection而不回滚事务

.net 在IP更改后重新连接丢弃的SqlConnection而不回滚事务,.net,sql,sql-server,tsql,.net,Sql,Sql Server,Tsql,我有多个客户端通过不可靠的(无线/gprs)网络连接到SQL Server,并在几分钟内执行大量小查询和插入。如果在此过程中网络连接断开,则整个事务将回滚并需要重新启动。由于业务需求,流程必须是事务性的(即,其他客户端可以看到来自其他客户端的完整数据集,或者根本看不到) 我希望能够检测到连接何时中断,能够重新连接到SQL Server,并在刚刚被删除的同一事务中继续处理,避免从一开始就重新启动。在打开连接后立即使用sp_getbindtoken时,将CommandTimeout设置为较小的值(比

我有多个客户端通过不可靠的(无线/gprs)网络连接到SQL Server,并在几分钟内执行大量小查询和插入。如果在此过程中网络连接断开,则整个事务将回滚并需要重新启动。由于业务需求,流程必须是事务性的(即,其他客户端可以看到来自其他客户端的完整数据集,或者根本看不到)

我希望能够检测到连接何时中断,能够重新连接到SQL Server,并在刚刚被删除的同一事务中继续处理,避免从一开始就重新启动。在打开连接后立即使用
sp_getbindtoken
时,将
CommandTimeout
设置为较小的值(比TCP KeepAlive小得多),如果在
ExecuteNonQuery
期间超时,我将打开到服务器的新连接,并从进程开始使用令牌调用
sp_bindsession
。然后,我使用绑定到前一个进程的事务的会话的新连接继续该进程

到目前为止,它工作得几乎完美,但根据,此API已被弃用,并将在SQL Server的未来版本中删除。问题是:如果没有这两个命令,我如何实现相同的结果?是否有其他方法可以从断开的TCP连接恢复事务

编辑/进一步信息:客户端应用程序正在带有条形码扫描仪的Windows CE设备上运行。我提供设备和软件,所以我可以自由地把我需要的任何东西放在那里。DB由第三方托管在受保护的环境中,我和客户都无法控制它。我每天总共要发送约50MB的销售数据。我可以使用SP保存数据,但它仍然需要传输,通过GPRS/EDGE链路向SP发出一个大参数的呼叫成功率接近0%


由于整个解决方案都在生产环境中工作,所以我希望将更改保持在最低限度。具有与
sp_bindsession
相同语义的替代API将是完美的。

您提供的MSDN链接建议使用。文章说,

MARS允许一个连接用于读取操作和数据操作语言(DML)操作,其中包含多个挂起的操作。此功能消除了应用程序处理连接繁忙错误的需要。此外,MARS可以取代服务器端游标的用户,这通常会消耗更多的资源。最后,由于多个操作可以在单个连接上操作,因此它们可以共享相同的事务上下文,从而无需使用sp_getbindtoken和sp_bindsession系统存储过程

通过这种方式,您可以使用BeginTransaction,事务将自动回滚,除非您显式提交它。您可以捕获commit语句的失败并递归地尝试重新提交它,直到事务的commit成功返回。只是个主意。也许是这样的:

private static void ExecuteSqlTransaction(string connectionString)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();

        SqlCommand command = connection.CreateCommand();
        SqlTransaction transaction;

        // Start a local transaction.
        transaction = connection.BeginTransaction("SampleTransaction");

        // Must assign both transaction object and connection
        // to Command object for a pending local transaction
        command.Connection = connection;
        command.Transaction = transaction;

        try
        {
            command.CommandText =
                "Insert into Region (RegionID, RegionDescription) VALUES (100, 'Description')";
            command.ExecuteNonQuery();
            command.CommandText =
                "Insert into Region (RegionID, RegionDescription) VALUES (101, 'Description')";
            command.ExecuteNonQuery();

            // Attempt to commit the transaction.
            transaction.Commit();
            //Both records are written to database.
        }
        catch (Exception ex)
        {
            // Attempt to roll back the transaction.
            try
            {
                transaction.Rollback();
            }
            catch (Exception ex2)
            {
                // This catch block will handle any errors that may have occurred
                // on the server that would cause the rollback to fail, such as
                // a closed connection.
                ExecuteSqlTransaction(connectionString);
            }
        }
    }
}

我只是不相信在一次交易中需要有~50MB的每日销售数据。我认为个人销售交易需要包装在sql交易中,但每个交易都更像1K。确实不能在存储过程中在服务器上运行多个小事务吗?如果每个设备必须是“全部”或“无”,则通过小事务将设备加载到暂存表。设备完成后,在事务中使用服务器上的存储过程刷新暂存表。或者在上传完成时,在上传完成后的一次更新中,只需在上传完成时放置一个布尔列,然后翻转该标志。一个50MB的事务实际上会破坏事务日志并锁定其他更新。

您是否考虑过让一个客户端-服务器应用程序使TSQL发生在硬连接到SQL server的服务器上(或者与SQL server是同一设备)?@BalamBalam:是,我创建了自己的实现IDbConnection的类,并将所有方法调用(缓冲)转发给自定义服务器,该服务器在SqlConnection上调用适当的方法。隧道是使用.NET远程处理通道完成的,并且足够健壮。不幸的是,现在应用程序部署在我无法在DB服务器上或附近放置自定义代码的环境中,因此我必须使用纯TSQL解决方案。多个无线客户端上的自定义代码是可以的,但单接线盒上的自定义代码是不可以的。这是一种奇怪的安全逻辑。不管逻辑与否,这听起来像是一个硬约束。由于事务被设计为回滚到开始,这充其量是有问题的。您是否真的在客户端上运行.net中的事务?您能将事务移动到服务器上的存储过程吗?@BalamBalam:我刚才在我的问题中提供了这些限制的进一步细节和原因。我想您误解了我的问题。失败不仅会发生在commit上,还会发生在其他每一条语句上。例如,如果有三次调用执行查询,第二次调用失败,我想继续执行第二次调用-您建议从第一次对账单开始重新启动。“销售数据”包括付款计划、详细信息、协议、附件、,文档扫描—它通常每天超过50MB,并且通过
readcommittedsapshot
隔离,无论您是否购买,它都工作得相当好。在小型事务中动态发送数据是可行的,但在部署系统时并非如此。重写应用程序的胆量不会很快得到批准。我问的是过时的API,而不是设计技巧,因为我一直坚持使用它。不过,谢谢你的反馈。如果在下一版本的SQL Server中删除sp_bindsession的话,我会选择临时表。我毫不怀疑它一天的容量是50MB。我怀疑的是这是一笔交易。交易的目的是为了