在实体框架中使用事务或锁定以确保正确操作
本文关键字:锁定 确保 操作 事务 框架 实体 | 更新日期: 2023-09-27 18:25:49
我对EF和SQL一般来说还很陌生,所以我需要一些帮助来澄清这一点。
假设我有一个表"钱包"(和EF代码第一对象钱包),它有一个ID和一个余额。我需要做这样的操作:
if(wallet.balance > 100){
doOtherChecksThatTake10Seconds();
wallet.balance -= 50;
context.SaveChanges();
}
正如你所看到的,它会检查一个条件是否有效,如果是,它必须先做一系列其他需要很长时间的操作(在这个夸张的例子中,我们说是10秒),然后如果通过,它会从钱包中减去50美元,并保存新数据。
问题是,还有其他事情可以随时改变钱包余额(这是一个网络应用程序)。如果发生这种情况:
- walletbalance=110
- 此操作通过了"if"检查,因为wallet.ballance>110
- 当它执行"doOtherChecksThatTake10Seconds()"时,用户从钱包中转出40美元
- 现在walletbalance=70
- "doOtherChecksThatTake10Seconds()"完成,从wallet.ballance中减去50,然后用新数据保存上下文
在这种情况下,walletbalance>100的检查不再为真,但由于延迟,操作仍然发生。我需要找到一种方法来锁定表,直到整个操作完成才释放它,这样在操作过程中就不会编辑任何内容。最有效的方法是什么?
需要注意的是,我曾尝试将此操作放入TransactionScope()中,我不确定这是否会产生预期效果,但我确实注意到,它开始导致与正在运行的完全不同的数据库操作发生大量死锁。
使用优化并发http://msdn.microsoft.com/en-us/data/jj592904
//Object Property:
public byte[] RowVersion { get; set; }
//Object Configuration:
Property(p => p.RowVersion).IsRowVersion().IsConcurrencyToken();
这允许脏读取。但是,当你去更新记录时,系统会检查rowversion在同一时间内没有改变,如果有人在这段时间内改变了记录,它就会失败。每次记录更改时,DB都会维护行版本。
开箱即用EF乐观锁定
您可以使用Transaction Scope。
导入命名空间
using System.Transactions;
并使用如下:
public string InsertBrand()
{
try
{
using (TransactionScope transaction = new TransactionScope())
{
//Do your operations here
transaction.Complete();
return "Mobile Brand Added";
}
}
catch (Exception ex)
{
throw ex;
}
}
另一种方法可以是使用一个或多个内部队列,并仅由一个线程使用该队列(生产者-消费者模式)。我在预订系统中使用这种方法,效果很好,非常简单。
在我的案例中,我有多个动态创建和删除的队列(每个"产品"一个)和多个使用者,其中只有一个使用者可以分配给一个队列。这也允许处理更高的并发性。在拥有大量用户的高并发场景中,您还可以使用单独的服务器和队列(如msmq)来处理此问题。
在一个票务系统中,当一部新的《哈利波特》上映时,很多用户都想拥有一张音乐会的门票,或者在购物系统中,这种方法可能会有问题,但我没有这种情况。