Entity framework 处理对单个数据库字段的多个更新

Entity framework 处理对单个数据库字段的多个更新,entity-framework,azure,Entity Framework,Azure,为了给我的问题提供一点背景知识,我有一个非常基本的银行系统。目前的过程是: 事务已添加到Azure服务总线 Azure Webjob会拾取此消息并在SQL数据库中创建新行 需要使用消息中的值(无论是+还是-)更新帐户的余额(总额) 例如,如果字段是10,我得到两个更新(10,-5),字段需要是15(10+10-5),这不是仅仅更新值的情况,它需要做一些算术 现在我不太确定如何处理余额的更新,因为可能会有很多请求,所以需要相应地更新 我认为一种方法是在SQL端而不是web作业上进行更新,但这对并发

为了给我的问题提供一点背景知识,我有一个非常基本的银行系统。目前的过程是:

  • 事务已添加到Azure服务总线
  • Azure Webjob会拾取此消息并在SQL数据库中创建新行
  • 需要使用消息中的值(无论是+还是-)更新帐户的余额(总额)
  • 例如,如果字段是10,我得到两个更新(10,-5),字段需要是15(10+10-5),这不是仅仅更新值的情况,它需要做一些算术

    现在我不太确定如何处理余额的更新,因为可能会有很多请求,所以需要相应地更新

    我认为一种方法是在SQL端而不是web作业上进行更新,但这对并发更新没有帮助

    我能在球场上锁定一下吗?但是,如果由于更新已在进行中而被阻止,更新会发生什么情况?它是等待还是失败?如果它等待,那么这应该是正常的。我用的是EF

    我想另一种方法是让另一个WebJob按计划运行,将所有金额相加并更新一次值,因此这将是唯一涉及该字段的内容


    多亏了这种或那种方式,您将需要序列化对帐户余额字段的写访问权限(实际上是整行)。
    如果系统上的写操作比读操作更频繁,或者您不必总是返回最新的余额,则可以使用一个单独的作业来拾取“挂起”插入,并最终更新余额。否则,要获得当前余额,您需要执行以下操作

    SELECT balance + 
        ISNULL((SELECT SUM(transaction_amount) 
        FROM pending_insert pi WHERE pi.user_id = ac.user_id
         ),0) as actual_balance
    FROM account ac
    WHERE ac.user_id = :user_id
    
    从性能的角度来看,这无疑是比较昂贵的,但对于某些系统来说,这是非常好的。另一个陷阱(同样,它可能与您的案件有关,也可能与您的案件无关)是强制执行非负余额

    或者,您可以通过以下方式始终如一地处理银行交易:

  • 开始数据库事务

  • 查找并锁定帐户表中的行

  • 如果需要,验证总金额

  • 在银行业务中插入记录

  • 更新用户帐户,即余额=余额+交易金额

  • 提交/回滚

    如果涉及多个用户帐户,您必须始终以相同的顺序锁定它们,以避免死锁

  • 这种方法更健壮,但从并发性的角度来看可能更糟(同样,这取决于应用程序中更新的性质-这里最坏的情况是一个用户有多个并发银行事务,多个用户的更新可以正常进行)


    最后,值得一提的是,因为您使用的是SQLServer,所以要小心锁升级导致的死锁。您可能需要在任何情况下实现一些重试逻辑

    您可能希望在sql中使用参数替换方法。您需要根据您在web工作中使用的编程语言了解如何做到这一点

    $updateval = -5;
    Update dbtable set myvalue = myvalue + $updateval
    
    code example:
    int qn = int.Parse(TextBox3.Text)
    SqlCommand cmd1 = new SqlCommand("update product set group1 = group1 + @qn where productname = @productname", con);
    cmd1.Parameters.Add(new SqlParameter("@productname", TextBox1.Text));
    cmd1.Parameters.Add(new SqlParameter("@qn", qn));
    

    然后执行。

    您使用的数据库是什么?@ReenactorRob我正在Azure中使用SQL数据库。我已经更新了问题来说明这一点。如果您想避免大量的update语句快速运行,您可以执行作业来收集数字,比如30秒,然后将它们相加,并将其添加到数据库中的当前余额值中。然后再次收集接下来30秒的值,求和并将其添加到db中的平衡值中。这样,数据库中的事务将减少,计算也将正确进行。