SqlBulkCopy.WriteToServer无法可靠地遵循BulkCopyTimeout

.net c# sqlbulkcopy sql-server-2008 timeout

我需要计算来自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 on vs. off
  • 目标作为堆表与索引表
  • 更长/更短的BulkTimeout值(10秒到5分钟)
  • 内部与外部交易

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

一般承认的答案

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

在批量复制操作期间获取批量更新锁定。

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

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

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

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

更新2:
同时在连接字符串中启用了多个活动结果集支持,每次都会一直超时。


热门答案

我有这个问题后来解决这个问题设置BulkCopyTimeout为零。

bulkCopy.BulkCopyTimeout = 0;


许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因