【发布时间】:2017-11-22 07:54:26
【问题描述】:
我正在尝试实现一个简单的服务(使用 C#、SQL Server、实体框架)来处理来自客户的付款,并预先进行几项检查(例如,单一产品一天不能购买超过 10 次)等)
代码的简化版如下:
public void ExecutePayment(int productId, PaymentInfo paymentInfo)
{
using (var dbContext = new MyDbContext())
{
var stats = dbContext.PaymentStatistics.Single(s => s.ProductId== productId);
var limits = dbContext.Limits.Single(l => l.ProductId == productId);
int newPaymentCount = stats.DailyPaymentCount + 1;
if (newPaymentCount > limits.MaxDailyPaymentCount)
{
throw new InvalidOperationException("Exceeded payment count limit");
}
// other limits here...
var paymentResult = ProcessPayment(paymentInfo); <-- long operation, takes 2-3 seconds
if (paymentResult.Success)
{
stats.DailyPaymentCount = newPaymentCount;
}
dbContext.SaveChanges();
}
}
我担心的是可能的并发问题。我需要确保没有 2 个线程/进程同时开始检查/更新stats.PaymentCount,否则统计信息将不同步。
我正在考虑将整个方法包装成一个分布式锁(例如使用this implementation),如下所示:
string lockKey = $"processing-payment-for-product-{productId}";
var myLock = new SqlDistributedLock(lockKey);
using (myLock.Acquire())
{
ExecutePayment(productId, paymentInfo);
}
但这种方法的问题在于 ProcessPayment 非常慢(2-3 秒),这意味着同一产品的任何并发支付请求都必须等待 2-3 秒才能开始限制检查。
任何人都可以为这种情况提出一个好的锁定解决方案吗?
【问题讨论】:
-
您是否也将付款存储在数据库中?我的意思是一些代表未决/失败/完成支付的支付对象。
-
@Evk,是的,SQL Server是目前各种应用数据唯一的存储机制
标签: c# sql-server entity-framework concurrency