【发布时间】:2017-02-13 15:11:54
【问题描述】:
我想对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 代码以及事务提交?如果没有,那还有什么其他的解决方案可以使用?
编辑1: 版本需要针对每个应用程序,而不是每行。
编辑2: 我可以使用可序列化的隔离级别,但由于这会导致性能问题,这不是一个选项。
【问题讨论】:
-
在我看来,最简单的解决方案是将所有这些 sql 代码移动到存储过程中并将其放入事务中。老实说,将 sql 从您的应用程序中移出无论如何都是一个好主意,以创建分层架构并将代码与数据实现分离。
-
@SeanLange 需要在现有系统上进行此更改,并且不能将整个逻辑移至存储过程。
标签: c# sql-server transactions optimistic-concurrency