如果两个请求在ASP.NET MVC应用程序中非常接近,我会遇到以下代码的竞争条件:
var workload = org.Workloads.SingleOrDefault(p => ...conditions...);
if (workload == null) {
workload = org.CreateWorkload(id);
}
workload
和org
是EntityFramework对象。对CreateWorkload
的调用会向数据库中的Workloads表添加一行。 (我们真的应该在表上使用UNIQUE约束强制执行此操作,但我现在不能表中包含一些脏数据。)对包含此代码的Action方法的后续调用将抛出SingleOrDefault
遇到满足条件的多行时的异常。
所以要解决这个问题,我想lock
这些代码行。我不希望每次请求都使用静态锁定对象,因为这会降低每个用户的网站速度。我想做的是使用Session.SyncRoot
进行锁定。即。
Workload workload;
lock (Session.SyncRoot)
{
workload = org.Workloads.SingleOrDefault(p => ...conditions...);
if (workload == null) {
workload = org.CreateWorkload(id);
}
}
然而,我不是ASP.NET专家,并且在文档和ReSharper中出现了一些警告信号,即它可以抛出NotImplementedExceptions或为null。但是,测试显示这很好用。
那么,ASP.NET专家说,使用Session.SyncRoot的风险是什么?作为替代方案,如果Session.SyncRoot“真的有风险”,我可以在Session启动时在Session集合中分配一个锁对象来做同样的事情吗?
答案 0 :(得分:2)
如果您使用实现HttpSessionStateBase
的自定义会话类但不覆盖SyncRoot
属性以执行除了抛出NotImplementedException之外的其他操作,则仅存在危险。 HttpSessionStateWrapper
类和HttpSessionState
类DO实现并覆盖SyncRoot
方法。因此,只要您通过HttpSessionStateWrapper
或HttpSessionState
类访问会话而不是自定义类,这就可以正常工作。