10

我需要计算来自 SqlBulkCopy 的连续超时异常。为了测试这一点,我使用外部应用程序启动事务并锁定目标表。

只有在第一次调用时,SqlBulkCopy 才会在预期时抛出超时异常。我们尝试过使用外部连接和事务,以及使用连接字符串和内部事务。对于外部连接和事务,无限等待永远不会在打开连接或开始或提交事务时,而是始终在.WriteToServer().

是否有某种方法可以SqlBulkCopy.WriteToServer()在达到.BulkCopyTimeout极限时可靠地抛出超时异常?

public void BulkCopy(string connectionString, DataTable table, int bulkTimeout)
{
    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(
        connectionString, 
        SqlBulkCopyOptions.UseInternalTransaction))
    {
    bulkCopy.BulkCopyTimeout = bulkTimeout;//e.g. 120 sec.
    //... fill with data, map columns...
    bulkCopy.WriteToServer(table);
    // ^^^^ waits indefinitely, doesn't throw until *after*
    //      the lock is released.
    }
}

我更喜欢让异常冒泡而不是在using块的范围内处理它们,但我总是可以重新抛出。非常感谢您的任何见解。

更新1:

还是没有解决。但是发现了有趣的行为——正常的 SqlCommand 将在同一锁定期间按预期抛出 TimeoutException,这使 SqlBulkCopy.WriteToServer 方法无限期挂起。

以下是我们尝试过的方法——但都失败了——让 SqlBulkCopy.WriteToServer 在预期的时候持续抛出超时:

  • MARS(多个活动结果集)开/关
  • TableLock 开启与关闭
  • 目的地作为堆表与索引表
  • 更长/更短的 BulkTimeout 值(10 秒到 5 分钟)
  • 内部与外部交易

现在,作为一种解决方法,我在 a) 将 WriteToServer 调用放在异步包装器中以便我可以自己计时,以及 b) 只调用 WriteToServer 一次;超时后,等到常规 SqlCommand成功后再尝试 WriteToServer。使用这些方法,我至少能够控制执行流程。

4

2 回答 2

5

您是否尝试过将 SqlBulkOptions.TableLock 选项传递给 SqlBulkCopy?该选项(引用)意味着它将:

在大容量复制操作期间获取大容量更新锁。

因此,如果有另一个处理锁定表,它将阻止获得锁,并且在理论上,可靠地超时。

更新:
我设置了自己的测试工具,但无法重现。为了锁定表,我在 SSMS 中启动了一个事务,执行SELECT * FROM TargetTable WITH (HOLDLOCK). 我使用了问题中包含的相同 BulkCopy 方法,使用内部事务,批量加载超时为 30 秒。每次尝试执行大容量复制都会在 30 秒后按预期超时。然后当我回滚 SSMS 事务时它会成功。

我使用的是 SQL Server 2008 Express、.NET 3.5。

不是在第一次尝试之后,批量加载超时没有正确传递吗?即它不是以某种方式设置为“无限期”。

更新 2:
还在连接字符串中打开了多个活动结果集支持,但我每次仍然始终超时。

于 2010-02-05T18:29:44.297 回答
2

后来我遇到了这个问题,为了解决这个问题,将 BulkCopyTimeout 设置为零。

bulkCopy.BulkCopyTimeout = 0;
于 2010-02-07T05:34:59.803 回答