c# - 具有可重复读取隔离的事务中的数据是否可能发生变化?

标签 c# sql-server entity-framework transactions transactionscope

我有一些 .NET 代码包含在一个可重复的读取事务中,如下所示:

using (
                var transaction = new TransactionScope(
                    TransactionScopeOption.Required,
                    new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead },
                    TransactionScopeAsyncFlowOption.Enabled))
            {
                int theNextValue = GetNextValueFromTheDatabase();
                var entity = new MyEntity
                               {
                                   Id = Guid.NewGuid(),
                                   PropertyOne = theNextValue, //An identity column
                                   PropertyTwo = Convert.ToString(theNextValue),
                                   PropertyThree = theNextValue,
                                   ...
                               };
                DbSet<MyEntity> myDbSet = GetEntitySet();
                myDbSet.Add(entity);
                await this.databaseContext.Entities.SaveChangesAsync();

                transaction.Complete();
            }

第一个方法,GetNextValueFromTheDatabase,检索存储在数据库表的列中的最大值。我正在使用可重复读取,因为我不希望两个用户读取和使用相同的值。然后,我只需在内存中创建一个 Entity 并调用 SaveChangesAsync() 将值写入数据库。

偶尔,我发现 entity.PropertyOne、entity.PropertyTwo 和 entity.PropertyThree 的值彼此不匹配。例如,entity.PropertyOne 的值为 500,但 entity.PropertyTwo 和 entity.PropertyThree 的值为 499。这怎么可能?即使代码未包含在事务中,我也希望这些值匹配(如果两个用户同时运行,则可能在实体之间重复)。

我正在使用 Entity Framework 6 和 Sql Server 2008R2。

编辑:
这是 GetNextValueFromTheDatabase

的代码
public async Task<int> GetNextValueFromTheDatabase()
{
    return await myQuerable
        .OrderByDescending(x => x.PropertyOne) //PropertyOne is an identity column (surprise!)
        .Select(x => x.PropertyOne)
        .Take(1)
        .SingleAsync() + 1;
}

最佳答案

所以这个问题无法明确回答,因为 GetNextValueFromTheDatabase 没有显示。我将按照您所说的去做:

SQL Server 中的

REPEATABLE READ S 锁定您已读取的行。当您读取当前最大值时,大概是从索引中读取的,该行是 S 锁定的。现在,如果出现新的最大值,则该行不受锁定影响。这就是为什么锁不会阻止其他竞争最大值出现的原因。

如果您通过从表中读取最大值来获取最大值,则需要SERIALIZABLE 隔离。这将导致您的特定情况出现死锁。这可以通过锁定提示或重试来解决。

您还可以保留一个单独的表来存储当前的最大值。 REPEATABLE READ 在这里就足够了,因为您总是访问该表的同一行。即使 REPEATABLE READ 没有锁定提示,您也会在这里看到死锁。

重试是解决死锁的有效方法。

关于c# - 具有可重复读取隔离的事务中的数据是否可能发生变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27828809/

相关文章:

c# - 使用单个 LINQ 查询使用 Entity Framework 删除多条记录

c# - 是否可以在 MVC 3 中打开/关闭验证数据注释?

c# - 使用 Windows 窗体图形绘制描边 - 需要改进性能

c# - 在 C# 中为 OrderedDictionary 连续赋值

c# - LINQ2SQL : Join multiple tables

sql-server - 数据库加密 : MSSQL 2008+ Database Encryption and use in Coldfusion

sql-server - "Microsoft Access database Engine"Hresult : 0X80004005 Description: "External Table is not in expected Format."

SQL Server - 在跟踪表中有效存储查询结果

.net - 我必须在 DbContext 上创建显式 DbSet 属性吗?

c# - 使用 AutoMapper 从实体映射到 DTO 或从 DTO 映射到实体时出错