ASP.NET|实体框架,竞争条件

本文关键字:竞争 条件 框架 实体 NET ASP | 更新日期: 2023-09-27 18:00:09

我有一个web应用程序,允许用户喜欢项目。每个项目都有一个他获得的总点赞数的属性。

当很多用户同时喜欢同一项时,就会出现问题,然后我在SQL中收到了不正确的值(由竞争条件引起)。

作为一个临时解决方案,我在控制器构造函数中创建了一个针对队列工作的工作线程,当接收到类似/不喜欢项的请求时,我将对该请求进行排队。工作线程正在对值进行反序列化,并更新一个将itemid映射到totalcount的字典。

然后,工作线程每一分钟更新一次数据库并得到结果。

附带问题:context.SaveChanges()是否只保存对象中更改的内容?还是保存对象的所有属性?

我有一种感觉,这个解决方案不是正确的,处理这样一个问题的最佳方法是什么?

ASP.NET|实体框架,竞争条件

当发生读写时,可以使用锁定数据的RepeatableRead事务范围:

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead }))
{
    ...
    context.SaveChanges();
    scope.Complete();
}

实体框架跟踪实体字段的更改,并生成sql代码以仅更新那些已修改的字段。您可以明确指定只更新一个实体属性,而忽略其他更改:

context.Entry(entity).State = EntityState.Unchanged;
context.Entry(entity)
        .Property(c => c.entityField).IsModified = true;

当您将对象附加到上下文中时,它也会很有用:

context.Attach(entity);
context.Entry(entity)
        .Property(c => c.entityField).IsModified = true;

因为Attach将实体及其属性放入处于Unchanged状态的上下文中。

对于性能和并发问题,最好使用ExecuteSqlCommand:

string sql = "UPDATE Table SET LikeCount = LikeCount+1 WHERE Id={0}";
using (var context = new BloggingContext()) 
{ 
    context.Database.ExecuteSqlCommand( sql, new SqlParameter("@Id", id)); 
}