我想使用樂觀併發與TransactionScope
。以下是我想出迄今代碼:TransactionScope和樂觀併發
var options = new TransactionOptions {IsolationLevel = IsolationLevel.ReadCommitted};
using (var scope = new TransactionScope(TransactionScopeOption.Required, options))
{
using (var connection = new SqlConnection(_connectionString))
{
// ... execute some sql code here
// bump up version
var version = connection.ExecuteScalar<DateTime>(@"
DECLARE @version datetime2 = SYSUTCDATETIME();
UPDATE [Something].[Test]
SET [Version] = @version
WHERE Id = @Id
SELECT @version
", new {Id = id});
// ... execute more sql code here
// check if version has not changed since bump up
// NOTE: version is global for the whole application, not per row basis
var newVersion = connection.ExecuteScalar<DateTime>("SELECT MAX([Version]) FROM [Something].[Test]");
if (newVersion == version) scope.Complete(); // looks fine, mark as completed
}
} // what about changes between scope.Complete() and this line?
不幸的代碼有一個嚴重的問題。在版本檢查和事務提交之間,數據庫可能會發生一些變化。這是一個標準的time of check to time of use錯誤。我可以看到解決它的唯一方法是將版本檢查和事務提交作爲單個命令執行。
是否有可能使用TransactionScope
執行一些SQL代碼以及事務提交?如果沒有,那麼還有什麼其他解決方案可以使
EDIT1: 版本需要是每個應用程序,而不是每行。
編輯2: 我可以使用可序列化的隔離級別,但它不是一個選項,因爲這會導致性能問題。
對我來說似乎最簡單的解決方案是將所有這些SQL代碼移動到存儲過程並將其放入事務中。無論如何,誠實地將sql移出應用程序是一個好主意,可以創建分層體系結構並將代碼與數據實現分離。 –
@SeanLange此更改需要在現有的系統上進行,並且將整個邏輯移動到存儲過程不是一種選擇。 –