16

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

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

UserId; Wallet Id; Balance

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

  1. 检查是否有足够的资金来执行该交易:
  2. 从余额中扣除交易成本。

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

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

我可以用 EF 实现这一目标吗?如果不是,我还有什么其他选择?

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

4

3 回答 3

11

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();
    }
}
于 2014-11-18T19:36:48.557 回答
5

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

YourDataContext.Database.BeginTransaction(IsolationLevel.RepeatableRead)

RepeatableRead 摘要:对查询中使用的所有数据加锁,防止其他用户更新数据。防止不可重复读取,但仍然可能出现幻像行。

于 2014-11-18T20:10:02.503 回答
4

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

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

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

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

有人在这里问这个问题:SQL Server:防止存储过程中的脏读

于 2014-11-18T19:50:54.377 回答