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();
}
问题是两个并发请求可能会为同一个用户创建两个无效的项目。对我来说,它看起来像是一段相当普通的代码,我想知道处理这种并发性问题的默认方式是什么。
您必须在应用程序上正确处理Concurrency Conflicts
。
1。悲观并发(锁)
如果您的应用程序确实需要防止意外数据丢失在并发场景中,实现这一点的一种方法是使用数据库锁。这被称为悲观并发。例如,在你读a之前从数据库中取出一行,请求只读锁或更新锁访问。如果锁定一行以进行更新访问,则其他用户不会锁定允许为只读访问或更新访问锁定行,因为他们会得到一份正在被修改的数据的副本。如果将一行锁定为只读访问,其他人也可以将其锁定为只读访问只读访问,但不能用于更新。
2。乐观并发
悲观并发的替代方案是乐观并发。乐观并发意味着允许并发冲突发生,然后,如果他们这样做了,就做出适当的反应。
请阅读使用实体框架处理并发文章获取更多信息。
如果一个项目的UserId和Name的组合应该是唯一的,则使其在数据库中是唯一的。
你可以尝试用静态锁定对象来解决这个问题…但这只会使它变得缓慢且难以理解/维护。
可以有两个独立的函数,一个用于创建,一个用于更新。或者你可以尝试更新,如果失败,创建它,不要忘记在数据库中添加唯一索引
如果UserId
字段被标记为唯一(或身份,这也是唯一的),你已经很好了。每当您进入一个小的时间间隔,同时添加多个具有相同UserId
的项目时,只有第一个项目会成功,其他所有项目都将失败。