2017-09-22 43 views
0

我们有一个电子商务网站,人们可以购买礼品卡。这些卡片存储在一个表格中,并按整数排序以达到物流目的。如果有人购买礼品卡,我们会在数据库中插入购买订单,并编辑第一张符合条件的卡片的字段,以便知道该卡片不再可用。锁表读

但是有时候2个用户在同一时间购买一张卡片时,两张卡片都是相同的。所以我们与IsolationLevel.ReadCommitted进行了交易,这是行不通的。对于4个同时点击,对于2 PurchaseOrder有1个相同的Card,对于2 PurchaseOrder有另外的Card

TransactionOptions transOption = new TransactionOptions(); 
transOption.IsolationLevel = IsolationLevel.ReadCommitted; 

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, transOption)) 
{ 
    PurchaseOrder purchaseOrder = GetFull(request.OrderId); 
    purchaseOrder.ChangeTracker.ChangeTrackingEnabled = true; 
    purchaseOrder.IdStatus = DbConstants.RefPurchaseOrderStatus.Completed; 

    //select the quantity of purchased gift cards and update them with ObjectContext.SaveChanges() 
    List<Card> cards = _cardBusiness.AssignCards(purchaseOrder.Quantity, purchaseOrder.IdProduct, purchaseOrder.IdUserAccount, purchaseOrder.IdChannel); 

    Card[] arrCards = cards.ToArray(); 

    int count = 0; 
    //Set a link between a PurchaseOrder Line and the Card 
    foreach(PurchaseOrderLine line in purchaseOrder.PurchaseOrderLines) 
    { 
     line.ChangeTracker.ChangeTrackingEnabled = true; 
     line.IdCard = arrCards[count].Id; 
     count++; 
    } 

    PurchaseOrder po = Update(purchaseOrder); 

    scope.Complete(); 

    return true; 
} 

快速评论:在交易中,我们得到了以前插入PurchaseOrder,改变其状态,然后选择一个可用的礼品卡(S),编辑一些属性,SaveChanges()并返回礼品卡(一个或多个)链接到PurchaseOrderLine

但我们显然没有锁定卡的选择。我们怎么能这样做?

更新:

public static List<Card> AssignCards(int qty, int idProduct, Guid idUserAccount, int? idChannel) 
{ 
    using (RestopolitanEntities context = GetContext()) 
    { 
     try 
     { 
      var Xcards = (from c in context.Cards 
         select c); 

      List<Card> cards = Xcards.OrderBy(c => c.IdOrder).Take(qty).ToList(); 

      foreach (Card card in cards) 
      { 
       card.ChangeTracker.ChangeTrackingEnabled = true; 
       card.UseDate = DateTime.Now; 
      } 

      context.SaveChanges(); 

      return cards.ToList(); 
     } 
     catch (Exception ex) 
     { 
      HandleException(ex); 
     } 
    } 
    return null; 
} 

这一次,我与IsolationLevel.RepeatableRead试过,一个Card不会再归因于2 PurchaseOrder。但是没有CardAssignCards()返回。对于4个同时点击,有2个PurchaseOrder,其中有1个不同的Card和2 PurchaseOrder而没有Card

+0

什么是AssignCards()?你可以添加这种方法的代码? – MikkaRin

+1

也许你可以创建一个数据库序列的解决方案,因为数据库将小心,你没有得到一个已经使用的号码... – DatRid

+0

你使用什么数据库平台? – mjwills

回答

1

无论是收购在交易开始的应用程序锁,

context.Database.ExecuteSqlCommand("exec sp_getapplock 'AssignCards','Exclusive';"); 

或使用标识卡使用查询一些锁提示:

var sql = "select top (@qty) CardId from Cards with (rowlock, updlock, readpast) where UseDate is null"; 
var cardIds = context.Database.SqlQuery<int>(sql,qty).ToList(); 

List<Card> cards = context.Cards.Where(c => cardIds.Contains(c.CardId)).ToList(); 

如果使用锁提示您可以使用READPAST提示来允许并发会话跳过被其他会话锁定的卡片。如果您使用Applciation锁,则可以在交易中间释放锁(选择卡后)。