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

时间:2017-01-06 15:25:12

标签: entity-framework azure

为了解决我的问题,我有一个非常基本的银行系统。目前的过程是:

  1. 将事务添加到Azure Service Bus
  2. Azure Webjob选择此消息并在SQL DB中创建新行。
  3. 帐户的余额(总计)需要使用邮件中的值进行更新(是+或 - )。
  4. 因此,例如,如果字段为10并且我得到两个更新(10,-5),则字段需要为15(10 + 10 - 5),不仅仅是更新值的情况,它需要做一些算术。

    现在我不太清楚如何处理余额的更新,因为可能会有很多请求进来,因此需要相应更新。

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

    我可以使用该字段进行锁定吗?但是,由于更新已在进行中,因此阻止更新会发生什么?是等待还是失败?如果它等待,那么这应该没问题。我使用的是EF。

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

    由于

2 个答案:

答案 0 :(得分:0)

无论如何,您需要序列化对帐户余额字段的写入权限(实际上是整行) 如果在您的系统上写入比读取更频繁,或者您不必总是返回最近的余额,那么单独的作业会选择“挂起”插入,并最终更新余额。否则,要获得当前余额,您需要执行类似

的操作
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

从性能角度来看,这肯定是更昂贵的,但对于某些系统来说,它非常好。另一个陷阱(再次,它可能与您的案例相关或不相关)是强制执行,例如,非负余额。

或者,您可以通过以下方式持续处理银行交易:

  1. 开始数据库事务
  2. 在帐户表中查找并锁定行
  3. 根据需要验证总金额
  4. 将记录插入banking_transaction
  5. 更新用户帐户,即balance = balance + transasction_amount
  6. 提交/回滚

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

  7. 这种方法更强大,但从并发的角度来看可能更糟糕(同样,它取决于应用程序中更新的性质 - 最坏的情况是一个用户的许多并发银行交易,对多个用户的更新将会更新精细)。

    最后,值得一提的是,由于您正在使用SQLServer,请注意锁定升级导致的死锁。您可能需要在任何情况下实现一些重试逻辑

答案 1 :(得分:0)

您可能希望在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));

然后执行。