并发表更新。 EF Core 事务

问题描述 投票:0回答:1
// here, sometimes getting old data or actual data but conflict updates, on multiple calls at the same time
var readyProduct = await _readyProductRepository.FindAsync(p => p.ModelId == readyProductCreate.ModelId);

if (readyProduct == null)
{
    readyProduct = _mapper.Map<ReadyProductCreate, ReadyProduct>(readyProductCreate);

    await _readyProductRepository.AddAsync(readyProduct);
}
else
{
    readyProduct.Count += readyProductCreate.Count;
    _readyProductRepository.Update(readyProduct);
}

var transaction = new ReadyProductTransaction
{
    ModelId = readyProductCreate.ModelId,
    Count = readyProductCreate.Count,
    Status = ReadyProductTransactionType.Import,
    Date = DateTime.Now,
};

await _transactionRepository.AddAsync(transaction);

await _unitOfWork.SaveAsync();

我用隔离级别

Transaction
覆盖了
Serializable
中的整个过程,但它造成了
deadlock

可能,在插入

trigger
表后创建一个
ReadyProductTransaction
来更新
ReadyProduct
表将是一个解决方案,但我想知道是否可以在没有触发器的情况下实现。

DbContext - 注册为作用域

所有存储库类,包括 UnitOfWork 类 - 注册为 Scoped

应用程序-.NET5.0

应用程序运行于 - IIS

c# asp.net-core entity-framework-core transactions
1个回答
0
投票

Serializable
事务更有可能(而非更少)导致死锁,因为它们锁定的次数更多、时间更长。 这并不意味着您不应该使用它们:更好的隔离总是更有利于数据完整性。您只需要正确使用它们即可。

始终确保以相同的顺序锁定表,并尝试确保在此类锁中使用相同的索引。

使用更新锁。这可以通过限制对独占锁的访问来防止死锁,同时仍然允许运行纯读查询。
    在某些 DBMS 中,这称为
  • SELECT FOR UPDATE
  • 。在 SQL Server 中,您可以向原始 SQL 查询添加
  • UPDLOCK
    提示。例如:
    
    
    var readyProduct = await _dbContext
        .FromSqlRaw<ReadyProduct>("SELECT * FROM dbo.ReadyProduct WITH (UPDLOCK)")
        .Where(p => p.ModelId == readyProductCreate.ModelId)
        .FirstOrDefaultAsync();
    
  • 话虽如此,首先考虑不要对数据进行非规范化。换句话说,不要将子行的计数存储在父表中。相反,在需要时查询子行的计数(可能使用索引视图)。

© www.soinside.com 2019 - 2024. All rights reserved.