ASP.用于更新实体的线程安全逻辑

本文关键字:安全 线程 用于 更新 实体 ASP | 更新日期: 2023-09-27 18:03:25

我有以下方法为某些用户添加或更新类型为Item的实体。这个方法是Service类的一部分,为每个请求创建一个新的实例。

public async Task SaveItem(int userId, string name)
{
    var item = await _context.Items.Where(i => i.UserId == userId).SingleOrDefaultAsync();
    if (item == null)
    {
        item = new Item
        {
            UserId = userId,
            Name = name
        };
        _context.Items.Add(item);
    }
    else
    {
        item.Name = name;
        _context.Entry(item).State = System.Data.Entity.EntityState.Modified;
    }
    await _context.SaveChangesAsync();
}

问题是两个并发请求可能会为同一个用户创建两个无效的项目。对我来说,它看起来像是一段相当普通的代码,我想知道处理这种并发性问题的默认方式是什么。

ASP.用于更新实体的线程安全逻辑

您必须在应用程序上正确处理Concurrency Conflicts

1。悲观并发(锁)

如果您的应用程序确实需要防止意外数据丢失在并发场景中,实现这一点的一种方法是使用数据库锁。这被称为悲观并发。例如,在你读a之前从数据库中取出一行,请求只读锁或更新锁访问。如果锁定一行以进行更新访问,则其他用户不会锁定允许为只读访问或更新访问锁定行,因为他们会得到一份正在被修改的数据的副本。如果将一行锁定为只读访问,其他人也可以将其锁定为只读访问只读访问,但不能用于更新。

2。乐观并发

悲观并发的替代方案是乐观并发。乐观并发意味着允许并发冲突发生,然后,如果他们这样做了,就做出适当的反应。

请阅读使用实体框架处理并发文章获取更多信息。

如果一个项目的UserId和Name的组合应该是唯一的,则使其在数据库中是唯一的。

你可以尝试用静态锁定对象来解决这个问题…但这只会使它变得缓慢且难以理解/维护。

可以有两个独立的函数,一个用于创建,一个用于更新。或者你可以尝试更新,如果失败,创建它,不要忘记在数据库中添加唯一索引

如果UserId字段被标记为唯一(或身份,这也是唯一的),你已经很好了。每当您进入一个小的时间间隔,同时添加多个具有相同UserId的项目时,只有第一个项目会成功,其他所有项目都将失败。