我有一些产品要出售,我想检查商店中产品的存在。 我使用实体框架和SQL Server。 我想要这样的想法。
IF ((SELECT TOP 1 Amount FROM tblProduct WHERE Id =1)>0)
UPDATE tblProduct
SET count = count -1
WHERE Id = 1
但这不是一次交易,当用户想同时购买时,我无法正确检查。我尝试过:
BEGIN TRANSACTION
IF ((SELECT TOP 1 Amount FROM tblProduct WHERE Id =1)>0)
UPDATE tblProduct
SET count = count -1
WHERE Id = 1
COMMIT
但事实并非如此。如何在实体框架中做到这一点。 谢谢
答案 0 :(得分:2)
据我了解,您正在尝试减少每次销售操作中的产品数量。 您需要原子地执行此操作,因为您需要避免出售缺货的产品。
有几种选择,例如在数据上保留版本的乐观锁,或为商品提供一次购买操作的分布式锁。
在sql中,您可以运行具有以下版本控制的更新语句:
update [table]
set count = count - 1
where id=1 and count=5 and version=3
每次更新都会锁定该行,因此如果另一个更新请求开始执行,它将等待当前更新,并且在执行时会影响0行。
您还可以将分布式锁与redis一起使用,并锁定进程本身。
这取决于需求,用例和您的资源。
对于使用实体框架执行此操作,如果首先使用代码,则可以执行以下方法:
// add the below property to your entity
[Timestamp]
public byte[] RowVersion { get; set; }
使用流利的api:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<YourEntity>().Property(s => s.RowVersion).IsConcurrencyToken();
//modelBuilder.Entity<YourEntity>().Property(s => s.RowVersion).IsRowVersion(); // in EF6 or EF Core
base.OnModelCreating(modelBuilder);
}
或者您可以使用 [ConcurrencyCheck] 属性:
[ConcurrencyCheck]
public int Version { get; set; }
[ConcurrencyCheck]
public int Count { get; set; }
EF会将这些列添加到更新查询中的where条件。如果受影响的行计数为0,则EF引发 DbUpdateConcurrencyException ,您需要捕获它。
查看更多信息:
https://docs.microsoft.com/en-us/ef/core/modeling/concurrency
Optimistic concurrency: IsConcurrencyToken and RowVersion
https://www.codeproject.com/Articles/817432/Optimistic-Concurrency-in-Entity-Framework-Code-Fi
http://www.binaryintellect.net/articles/14e67064-634c-4206-9eca-a42d3739594a.aspx
答案 1 :(得分:1)
您可以尝试其他实现方法。例如,仅在有数量时执行更新:
UPDATE tblProduct
SET count = count -1
WHERE Id = 1
AND Amount > 0;
通过这种方式,select
语句中不再需要。或者,您可以添加check constraint
以确保count
始终为> 0
,并让SQL引擎应用ACID属性。如果用户(事务)以某种方式尝试将计数减少到0以下,则将引发错误,您可以在应用程序中捕获该错误(例如)。