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合法嗎? 是的,了解原因