在数据库上执行“atomic”操作“IncreaseIf”

时间:2012-09-26 11:25:59

标签: c# visual-studio entity-framework transactions atomic

我需要对某些实体框架模型的某些字段执行 atomic 操作检查值,如果其值为0则增加它。

我想过交易,就像:

bool controlPassed = false;
using (TransactionScope scope = new TransactionScope())
{
    var model = ...ModelEntities.first_or_default(...)
    if (model.field == 0){
        ++model.field;
        ...saveChanges();
        controlPassed = true;
    }
    scope.Complete();
}
if (controlPassed)
{
    ...
    using (TransactionScope scope = new TransactionScope())
    {
        --model.field;
        ...saveChanges();
        scope.Complete();
    }
}

当然,一切都在尝试捕捉等等。

我的问题是:它会如何运作?

真的很难检查。 我有多线程应用程序。

是否有可能两个或更多线程通过控制(检查field == 0并增加它)?

数据库(数据库,表格,行,字段)中是否会阻止输出?

我不能让两个或多个线程同时位于controlPassed部分。

1 个答案:

答案 0 :(得分:10)

  

是否有可能两个或更多线程通过控制   (检查该字段== 0并增加它)?

您有Serializable个交易(TransactionScope的默认值)。这意味着可以有两个带有字段== 0的线程,但是在发生死锁之后立即发生,因为第一个线程的事务在字段上保持共享锁,第二个线程的事务为同一个字段保存另一个共享锁。这些事务都不能将锁升级为独占以保存更改,因为它们在其他事务中被共享锁阻止。我认为RepeatableRead隔离级别会发生同样的情况。

如果您将隔离级别更改为ReadCommitted(使用MS SQL Server时SaveChanges的默认设置为TransactionScope),答案将再次为是,但这次没有死锁,因为EF使用正常选择没有任何表提示 - 这意味着当select完成时,不会保留记录上的锁。仅保存更改(修改)锁定记录,直到事务提交或回滚。

要使用select锁定ReadCommitted事务中的记录,必须使用本机SQL查询和UPDLOCK(在select期间锁定记录以进行更新并保持它直到事务结束)表提示。 EF查询不支持表提示。

编辑:我写了a long article about pessimistic concurrency,其中描述了为什么您的解决方案无法正常工作以及必须进行哪些更改才能使其正常运行。