如何在实体框架中完全锁定一行

Posted

技术标签:

【中文标题】如何在实体框架中完全锁定一行【英文标题】:How to totally lock a row in Entity Framework 【发布时间】:2015-01-16 02:57:05 【问题描述】:

我正在处理我们正在处理货币交易的情况。

例如,我有一张用户钱包表,他们的余额在该行中。

UserId; Wallet Id; Balance

现在在我们的网站和网络服务中,每次发生特定交易时,我们需要:

    检查是否有足够的资金来执行该交易: 从余额中扣除交易费用。

在我的整个交易期间锁定该行/实体的正确方法是什么?

根据我的阅读,有一些解决方案,其中 EF 标记一个实体,然后在将其保存回数据库时比较该标记,但是当另一个用户/程序已经编辑了该数量时它会做什么?

我可以用 EF 实现这一点吗?如果没有,我还有什么其他选择?

调用存储过程是否可能允许我正确锁定该行,以便在程序 A 锁定该行时其他人无法访问 SQL Server 中的该行?

【问题讨论】:

【参考方案1】:

EF 没有内置锁定机制,您可能需要使用原始查询,例如

using (var scope = new TransactionScope(...))

    using (var context = new YourContext(...))
    
        var wallet = 
            context.ExecuteStoreQuery<UserWallet>("SELECT UserId, WalletId, Balance FROM UserWallets WITH (UPDLOCK) WHERE ...");

        // your logic

        scope.Complete();
    

【讨论】:

【参考方案2】:

您可以在实体框架中设置事务的隔离级别,以确保没有其他人可以更改它:

YourDataContext.Database.BeginTransaction(IsolationLevel.RepeatableRead)

可重复读取 概括: 对查询中使用的所有数据进行锁定,以防止其他用户更新数据。防止不可重复读取,但仍然可以使用幻像行。

【讨论】:

【参考方案3】:

事务性数据库的全部意义在于数据的使用者决定了他们对数据的看法应该是多么孤立。

无论您的事务是否为serialized,其他人都可以对您刚刚更改但未提交的相同数据执行脏读。

您应该首先关注您的视图的完整性,然后只接受该视图质量的降低,以在您确定需要的地方提高系统性能。

Serialized 隔离级别将所有内容包装在TransactionScope 中,您个人不会真的出错。仅在您认为确实需要隔离级别时才降低隔离级别(即有时出错时可以)。

有人在这里问这个问题:SQL Server: preventing dirty reads in a stored procedure

【讨论】:

SERIALIZABLE 的重要之处在于它是一种获得如同单线程执行的相当安全的方法。自动更正。 是的;这就是为什么它是最好的起点!从绝对安全开始,只有在需要并正确了解后果后才偏离。

以上是关于如何在实体框架中完全锁定一行的主要内容,如果未能解决你的问题,请参考以下文章

实体框架:如何从具有复合键的表中返回一行?

为啥实体框架在保存时锁定表?

实体框架事务锁定

在 BigTable 数据存储中,关于并发性,我如何“锁定”实体?

如何使用 Entity Framework 在读取时锁定表?

如何在实体框架中设置默认值