【问题标题】:Safely transfer credit from one user to another安全地将信用从一个用户转移到另一个用户
【发布时间】:2017-01-10 17:54:51
【问题描述】:

我在一个网站上工作,我在其中使用带有 Entity Framework 6 的 Asp.Net MVC。每个用户都有一个信用,有时用户可以将他们的信用转移给其他用户。简单的方法是这样的:

public class ApplicationUser : IdentityUser
{
    //....
    public decimal Credit { get; set; }
}

var user1 = await db.Users.FindAsync(id1);
var user2 = await db.Users.FindAsync(id2);
user1.Credit -= amount;
user2.Credit += amount;

await db.SaveChangesAsync();

但是,我认为这很容易受到并发问题的影响。例如,如果 2 个用户同时转移给一个用户怎么办?

由于我们将在网站上使用真钱作为信用,那么解决此问题的最安全和防故障的方法是什么?

【问题讨论】:

  • 容易并发?你测试过吗?因为我做这些事情,如果有不连贯的风险,我会立即改变它......
  • 我认为 ASYNC 正是为这类事情而设计的,但是,如果其中有金钱交易,您应该有一个带有交易 ID 的交易表,这样您就可以追踪一切......跨度>
  • 您可以在模型中配置并发列,以便保护更新。你可以有一个DateTime ModifiedOn { get; set; } 属性。

标签: c# asp.net-mvc entity-framework concurrency


【解决方案1】:
【解决方案2】:

默认情况下,EntityFramework 会将SaveChanges() 包装到事务中。所以你的改变要么成功要么一起失败。

你可以做什么:

事务包装器

  1. 您可以将代码显式包装到 TransactionScope() 中

    使用 (TransactionScope 范围 = new TransactionScope()) { // 需要在事务中以原子方式工作的代码 }

或者

事务表

  1. 使用更好的数据库设计来存储事务而不是最终状态

这是银行的做法。每当交易发生时,将一个帐户的借记和贷记存储到另一个帐户。

  • 从乔那里拿 -50
  • 给简+50

然后,当您查询用户的余额时,您会根据他们所有交易的总和来汇总最终余额(对于任何支持 SQL 的 DBMS 来说都很容易)

【讨论】:

  • 感谢您的回答。你能给我一个第二个选项的代码示例吗?我对银行对此的处理方式更感兴趣
  • 另外,如果一个用户有很多交易行,那会不会在一段时间后给网站带来开销?它不会减慢查询速度吗?
【解决方案3】:

建议:

  1. 让您的流程先从旧帐户中取出资金,然后确认交易已过帐到旧帐户,然后将资金应用到新帐户。

  2. 在每次转账时记录一个序列号,并在过帐到他们的帐户时确认该交易具有该交易的正确序列号。这只是一种很好的做法,因此您也可以记录每次传输的日志。

  3. 将债务过帐到源帐户后,确认帐户余额不是负数。如果是,取消交易。这可以防止对现有余额进行多次借记,然后在将每笔债务应用于源账户后最终变为负数(增加了安全隐患)。此外,请确保转移的金额是正数。一个简单的黑客骗局是从别人的账户中转出负数(从而增加黑客的账户)。

如果您不信任您使用的框架,有很多方法可以手动执行此操作,并且应该执行其中许多检查以降低欺诈风险。

您可以锁定两条记录,进行传输,然后解锁两条记录。在锁定之前,请确保它们尚未锁定。这样,两个记录都会被锁定,直到事务完成。

没有什么能取代对事务日志的需求,恕我直言。

【讨论】:

  • 我想框架应该能够处理这样的事情。尝试为此类事情提出手动解决方案通常会引入更多问题本身。 EF 对此没有任何意见吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-10
  • 1970-01-01
  • 1970-01-01
  • 2016-03-26
  • 2016-07-02
  • 1970-01-01
  • 2011-09-01
相关资源
最近更新 更多