最近我們遇到了一個與SQL事務超時有關的非常有趣的問題。超時的聲明其實並不重要的問題的緣故,但它是一個INSERT語句W/O生成的GUID作爲重點與客戶明確的交易:防範SQL事務超時的方法
INSERT MyTable
(id, ...)
VALUES (<client-app-generated-guid>, ...)
我們也有就地重試政策,所以如果命令失敗並返回SqlException,那麼它將被重試。 SQL Server(Azure SQL)有一天沒有正常運行,我們在重試期間遇到了很多奇怪的PK違例錯誤。他們是由重試實際上成功承諾上的SQL Server事務(以便導致插入與已採取的ID)。我知道SQL超時是purely client side concept,所以如果客戶認爲SqlCommand失敗 - 它可能或可能不是的意思。
我懷疑客戶端顯式事務控制通過例如包裝報表TransactionScope
如下圖所示將修復99%的此類問題 - 因爲Commit其實很快&廉價操作。不過,我仍然在那裏看到警告 - 在提交階段也會發生超時。應用程序再次可能處於不可能猜測交易是否真正承諾的情況(以找出重試的必要性)。
問題是如何編寫防彈編碼(對於這種類型的問題)和通用時尚,並且只有在確認交易未提交時才重試。
using (var trx = new TransactionScope())
using (var con = GetOpenConnection(connectionString))
{
con.Execute("<some-non-idempotent-query>");
// what if Complete() times out?!
// to retry or not to retry?!
trx.Complete();
}
即使框架代碼確實有99%的報告提交事務的方式,如果您很快,仍然可以在客戶端從SQL Server獲得確認COMMIT TRAN實際上已成功執行之前拔出插件。我認爲這可能是SQL Azure中的一個問題,而僅僅因爲SQL Azure調用的SLA /延遲導致的on-premesis問題更少。 沒有辦法告訴您提交是否成功。即使是寫後讀也可能會讓某人在高容量環境中發生變化。 – PhillipH
@PhillipH,謝謝!那麼如何克服這些問題呢? –
如果您的提交失敗,在重試處理邏輯中,您可能需要執行條件重新插入,如在INSERT ... WHERE NOT EXISTS(SELECT ID FROM MyTable WHERE id = @id)中那樣' – Alex