我有一个管理控制器类,管理任务需要在同一个操作方法调用上添加和删除实体,所以我担心当多个管理员同时访问同一个操作方法时,一些Add操作将会从第一个事务启动,而其他Add操作将从第二个事务启动。这可能会导致最终结果出现不一致的结果。由于一些Add&删除操作将从TransactionOne启动,而另一个操作将从transactionTwo启动。 例如,我有一个动作方法: -
[Authorize]
public class SecurityRoleController : Controller
{
Repository repository = new Repository();
//code goes here
[HttpPost]
public ActionResult AssignPermisionLevel2(ICollection<SecurityroleTypePermision> list, int id)
{
repository.DeleteSecurityroleTypePermisions(id);
foreach (var c in list)
{
repository.InsertOrUpdateSecurityroleTypePermisions(c,User.Identity.Name);
}
repository.Save();
return RedirectToAction("AssignPermisionLevel", new { id = id });
}
调用以下repertory方法,为同一个action方法调用执行添加和删除操作: -
public void DeleteSecurityroleTypePermisions(int securityroleID)
{
var r = tms.SecurityroleTypePermisions.Where(a => a.SecurityRoleID == securityroleID);
foreach (var c in r) {
tms.SecurityroleTypePermisions.Remove(c);
}
}
以及以下存储库方法: -
public void InsertOrUpdateSecurityroleTypePermisions(SecurityroleTypePermision role, string username)
{
var auditinfo = IntiateAdminAudit(tms.AuditActions.SingleOrDefault(a => a.Name.ToUpper() == "ASSIGN PERMISION").ID, tms.SecurityTaskTypes.SingleOrDefault(a => a.Name.ToUpper() == "SECURITY ROLE").ID, username, tms.SecurityRoles.SingleOrDefault(a=>a.SecurityRoleID == role.SecurityRoleID).Name, tms.PermisionLevels.SingleOrDefault(a=>a.ID== role.PermisionLevelID).Name + " --> " + tms.TechnologyTypes.SingleOrDefault(a=>a.AssetTypeID == role.AssetTypeID).Name);
tms.SecurityroleTypePermisions.Add(role);
InsertOrUpdateAdminAudit(auditinfo);
}
为了避免任何意外结果,我决定在我的动作方法中加入一个锁,如下所示: -
[Authorize]
public class SecurityRoleController : Controller
{
Repository repository = new Repository();
public static object REQUEST_LOCK = new object();
//code goes here
[HttpPost]
public ActionResult AssignPermisionLevel2(ICollection<SecurityroleTypePermision> list, int id)
{
lock (REQUEST_LOCK)
{
repository.DeleteSecurityroleTypePermisions(id);
foreach (var c in list)
{
repository.InsertOrUpdateSecurityroleTypePermisions(c, User.Identity.Name);
}
repository.Save();
return RedirectToAction("AssignPermisionLevel", new { id = id });
}
}
所以任何人都可以建议,如果我正在做的是正确的方式,并且我的行动方法中的Lock会影响性能还是有我不知道的缺点? 此致
答案 0 :(得分:2)
我可以问你为什么删除然后插入新记录?为什么不更新现有记录?这将首先避免对锁的需要,因为RDBMS将通过在更新进行时锁定要更新的记录来自动处理这种情况(在真正的关系语义中,更新是删除然后重新添加新值 - 但我怀疑实际的RDBMS实现是否专门做了这一点,但它们必须保证ATOMICity与数据操作有关。)
无论如何,是的,如果您期望大量用户同时访问您的网站,这可能会对性能产生影响(我在考虑每秒数千个请求 - 纯猜想的顺序) 。从本质上讲,在调用此操作方法时,您正在将异步多线程应用程序转换为同步单线程应用程序。
换句话说,如果这个设计会对性能产生任何影响,那么这个动作方法几乎肯定会成为瓶颈。
确定性能影响的唯一方法是对网站执行负载或压力测试,尤其是每秒对此方法的数千(近)同时请求。
更新:我看到你有一个名为InsertOrUpdateSecurityroleTypePermission
的方法。您应该将此方法/存储过程分为两个,一个插入,另一个更新。这样,正如我之前所说,你可以完全避免潜在的线程/ ATOMICity问题。
更新2:
好吧,我想我发现了导致不必要复杂性的设计决策。相反,您可以使用事务来设计存储过程,以按照规定的顺序处理添加/删除必要记录以完成任务。这样,你就是利用数据库来确保这一切都是在原子上发生的;并且使用事务,如果某些内容无效或无法完成(当前代码不会执行),您可以ROLLBACK
,这样您就可以摆脱{{1}在你的行动方法中。此外,您仍然可以使用EF-EF来调用您在数据库中创建的存储过程。就并发用户而言,使用这种方法,您仍然会有“最后写入获胜”的情况(例如顺序“访问”)。