[英]Handle race condition
我正在使用ASP.NET MVC和Entity Framework(版本5)开发财务应用程序。
在我的应用程序中,用户可以批准或拒绝交易。 如果用户批准,将转移资金并批准通知电子邮件,否则将发送拒绝通知电子邮件。
我关心的是 ,如果两个用户同时批准同一个交易。 用户将获得事务状态“WaitForApprove”并进行双重转移(如果两个用户都批准)。
我如何处理这种情况 ,什么是最好的解决方案(理智和低资源消耗)。
我做了一些研究,我发现Mutex可以解决这个问题。 但我不确定这是最好的解决方案。
这是我的原始代码看起来像(Mutex未应用)。
public void TransactionApproval(int sysTransferInfoID, string username, string command)
{
// Get the transaction.
var info = _transInfoRepo.GetSingle(i => i.SYS_TRANSFER_INFO_ID == sysTransferInfoID);
if (info.SYS_TRANSFER_STATE_ID != (int)eTransferState.WaitForApprove) // Check status.
{
if (command == "Approve")
{
// Call another service to make transfer here.
// Sent approve fund transfer notification email to other users.
info.SYS_TRANSFER_STATE_ID = (int)eTranferState.Approved; // Change status.
info.APPROVE_BY = username;
}
else if (command == "Reject")
{
// Sent reject fund transfer notification email to other users.
info.SYS_TRANSFER_STATE_ID = (int)eTranferState.Rejected; // Change status.
info.APPROVE_BY = username;
}
_context.SaveChanges();
}
else
{
throw new Exception("Cannot approve transaction.");
}
}
您需要完全分离从用户界面转移资金的责任。 不允许用户界面直接设置传输状态。
相反,在对象上公开方法,例如ApproveTransfer()和RejectTransfer(),它们检查对象的当前状态,并仅在对象处于适当状态时执行请求的操作。
该对象还需要一种机制来确保任何对象实例都知道适当的状态,甚至是在不同的对象实例(可能在不同的服务器上)启动所请求的操作之后创建的状态。 为此,您必须转到数据库。
在数据库中保存该状态的最佳策略取决于您实际执行事务的方式。
如果必须在对象上设置一个标志(可能由另一个进程选取),那么具有乐观并发性的数据库事务就足够了。
如果您的对象正在启动对其他系统的调用(可能是Web服务调用以启动传输),则需要锁定数据库中的行(具有隔离级别可重复读取的事务)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.