我目前正在创建一个系统,允许用户要求优惠券,在优惠券被认领后,他们的帐户上的接收货币。
最近我遇到了一个问题,如果两个具有相同优惠券代码的请求在几乎完全相同的时间被触发,我的web服务调用将同时接受这两个请求(可能是因为写入数据库所需的时间)。
有问题的代码:
var userId = User.Identity.GetUserId();
var coupon = Context.Coupons.SingleOrDefault(c => c.Code == code && c.Deleted == false);
if (coupon == null)
return BadRequest("The code you entered does not belong to a coupon.");
coupon.UserId = userId;
coupon.Deleted = true;
await Context.SaveChangesAsync();
Give the user balance...
return Ok();lock (lockObj)
{
var userId = User.Identity.GetUserId();
var coupon = Context.Coupons.SingleOrDefault(c => c.Code == code && c.Deleted == false);
if (coupon == null)
return BadRequest("The code you entered does not belong to a coupon.");
coupon.UserId = userId;
coupon.Deleted = true;
Context.SaveChanges();
Give the user balance...
}
return Ok();所以我的问题是:这是解决这个问题的合法方法吗?如果很多人同时索取优惠券,恐怕会成为一个问题。有没有更好的方法来解决这个问题?
发布于 2017-02-01 21:00:26
简单的回答也许是。如果这是唯一更新它的代码,那么您会很好,但是您正在创建一个网关,即使他们有不同的代码,一次只有一个人可以更新。如果您的网站变得很大,您将有性能问题。
如果可能的话,应该让数据库处理并发性。如果使用SQL,则应使用rowversion字段或时间戳字段(如果是旧的SQL )。然后使用TimeStampAttribute配置实体,如果使用fluent,则配置等时标记方法。每当字段被更改时,SQL都会自动更改此值。如果您进行了更新,并且该值发生了更改,那么Entityframe将使用它并抛出一个OptimisticConcurrencyException。您可以捕获该错误,并知道自检索该数据以来数据已发生更改。
发布于 2017-02-02 11:31:56
尝试处理这样的锁定问题可能是个坏主意,因为当侧倾(添加新的服务器/实例)时,这个问题仍然存在。
我建议在SQL中使用并发方法(如@CharlesNRice所建议的),或者使用某种消息队列解决方案,该解决方案旨在处理并发问题。
发布于 2017-02-02 20:16:09
实体框架事务是其内部架构的一部分。"SaveChanges()“方法在事务中操作并保存工作结果。
using (var context = Context)
using (var dbcxtransaction = context.Database.BeginTransaction())
{
try
{
// coupon code here
context.SaveChanges();
dbcxtransaction.Commit();
}
catch
{
dbcxtransaction.Rollback();
}
}https://codereview.stackexchange.com/questions/154201
复制相似问题