【问题标题】:Ensure concurrent (money) transactions in Entity Framework?确保实体框架中的并发(金钱)交易?
【发布时间】:2015-06-07 10:05:15
【问题描述】:

假设我有一个account_profile 表,它的Score 字段类似于帐户的钱(数据库类型是BIGINT(20),EntityFramework 类型是long,因为我不需要小数) .现在我有以下功能:

public long ChangeScoreAmount(int userID, long amount)
{
    var profile = this.Entities.account_profile.First(q => q.AccountID == userID);

    profile.Score += amount;

    this.Entities.SaveChanges();

    return profile.Score;
}

但是,我担心当ChangeScoreAmount被同时调用多次时,最终的数量将不正确。

这是我目前正在考虑的解决方案:

  • ChangeScoreAmount 函数中添加一个带有静态锁定变量的锁,因为类本身可能在需要时被实例化多次。它看起来像这样:

    public long ChangeScoreAmount(int userID, long amount)
    {
        lock (ProfileBusiness.scoreLock)
        {
            var profile = this.Entities.account_profile.First(q => q.AccountID == userID);
    
            profile.Score += amount;
    
            this.Entities.SaveChanges();
    
            return profile.Score;
        }
    }
    

问题是,我从未尝试过锁定static 变量,所以我不知道它是否真的安全,是否会发生死锁。此外,如果在此函数之外的其他地方,中途应用了对 Score 字段的更改,则可能会很糟糕。

好的,这不再是一个选项,因为我的服务器应用程序将在多个站点上运行,这意味着无法使用锁定变量

  • 在数据库中创建存储过程并在函数中调用该存储过程。但是,我不知道是否有一种“原子”方式来创建该存储过程,以便一次只能调用一次,因为我仍然需要检索值,更改它然后再次更新它?

我正在使用 MySQL Community 5.6.24 和 MySQL .NET Connector 6.9.6,以防万一。

注意我的服务器应用程序可能在多台服务器机器上运行。

【问题讨论】:

标签: c# mysql entity-framework transactions atomic


【解决方案1】:

您可以使用具有可重复读取隔离级别的 sql 事务,而不是锁定应用程序。比如你可以写

public long ChangeScoreAmount(int userID, long amount)
{
    using(var ts = new TransactionScope(TransactionScopeOption.RequiresNew, 
        new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead })
    {
      var profile = this.Entities.account_profile.First(q => q.AccountID == userID);

      profile.Score += amount;

      this.Entities.SaveChanges();

      ts.Complete();

      return profile.Score;
    }    
}

当您没有提交或回滚时,交易保证 accountprofile 记录不会在 db 中更改。

【讨论】:

  • 当我的服务器有多个应用程序实例时,或者当我的应用程序在多台服务器机器上运行时应用它?我相信代码是数据库之外的服务器端?
  • 无论您拥有多少应用程序实例或服务器机器。数据库中的事务和数据库引擎防止任何更改(来自其他事务)以可重复的读取隔离级别在您的事务中读取的记录。
  • 我能再问一个问题吗,TransactionScope 参数中既没有Connection 也没有Entities 对象,它怎么知道要“隔离”和“活在数据库中”和数据库引擎”? “如果”我有两个数据库连接同时工作怎么办?
  • 创建 TransactionScope 实例后,您可以通过 Transaction 类的静态属性 Transaction.Current 访问当前线程中的当前 Transaction。当 ado.net 命令执行时,它会查看 Transaction.Current 和它的隔离级别,然后将 begin transaction 命令传递给数据库。如果您在同一个线程中有两个数据库连接,那么在它们上执行的所有命令都将成为一个分布式事务的一部分。如需更多信息,请点击此处codeguru.com/csharp/.net/net_data/sortinganditerating/…
  • 非常感谢,现在对我有意义!
猜你喜欢
  • 2016-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-02
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
相关资源
最近更新 更多