2017-09-22 46 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鎖,則可以在交易中間釋放鎖(選擇卡後)。