我有多个客户端通过不可靠(无线/ gprs)网络连接到SQL Server,并在几分钟内执行大量小型查询和插入。如果在此过程中网络连接中断,则会回滚整个事务并需要重新启动。由于业务需求,流程必须是事务性的(即其他客户端看到来自其他客户端的完整数据集或根本看不到它。)
我希望能够检测连接何时中断并能够重新连接到SQL Server并继续处理刚刚删除的同一事务中的,并避免从一开始就重新启动。目前我在打开连接后立即使用sp_getbindtoken
,将CommandTimeout
设置为较小的值(远小于TCP KeepAlive),如果在ExecuteNonQuery
期间出现超时,则打开与服务器的新连接,从进程开始使用令牌调用sp_bindsession
。然后我继续使用绑定到先前进程'transaction'的会话的新连接进行处理。
到目前为止它的工作几乎完美,但根据MSDN,此API已弃用,将在SQL Server的未来版本中删除。问题是:如果没有这两个命令,我怎样才能获得相同的结果?有没有其他方法可以从丢弃的TCP连接中恢复事务?
编辑/更多信息:客户端应用程序在带有条形码扫描程序的Windows CE设备上运行。我提供设备和软件,所以我可以随意放置任何我需要的东西。数据库由第三方托管在受保护的环境中,我和客户都无法控制它。我总共要发送约50MB的每日销售数据。我可以使用SP来保存数据,但它仍然必须传输,并且一个大的参数对SP的一次调用在GPRS / EDGE链接上成功率接近0%。
由于整个解决方案在生产环境中工作,我希望将更改保持在最低限度。与sp_bindsession
具有相同语义的替代API将是完美的。
答案 0 :(得分:2)
我只是不买那个〜50MB的每日销售数据需要在一次交易中。我买单个sales-tansactions需要包含在sql-transaction中,但那些更像是每个1K。您确定无法在存储过程中在服务器上运行多个小事务吗?如果它必须是来自每个设备的全部或全部,则通过小事务将设备加载到临时表。完成设备后,在事务中使用服务器上的存储过程来刷新登台表。或者只是在完成上传时放置一个布尔列,然后在上传完成时在单个更新中翻转该标志。一个50MB的交易真的会破坏交易日志并锁定其他更新。
答案 1 :(得分:0)
您提供的MSDN链接建议使用MARS。根据文章:
MARS允许连接用于具有多个挂起操作的读取操作和数据操作语言(DML)操作。此功能消除了应用程序处理连接繁忙错误的需要。此外,MARS可以替换服务器端游标的用户,这通常会消耗更多资源。最后,因为多个操作可以在单个连接上运行,所以它们可以共享相同的事务上下文,从而无需使用sp_getbindtoken和sp_bindsession系统存储过程。
这样您就可以使用BeginTrasaction,除非您明确提交,否则事务将自动回滚。您可以捕获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);
}
}
}
}