0

我有一个管理控制器类,管理任务需要在同一个action方法调用上添加和删除实体,所以我担心当多个管理员同时访问同一个action方法时,一些添加操作会从第一个事务,而其他 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 方法,该方法对同一操作方法调用执行添加和删除操作:-

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 会影响性能还是有我不知道的缺点?问候

4

1 回答 1

2

请问您为什么要删除然后插入新记录?为什么不更新现有记录?这将首先避免需要锁定,因为 RDBMS 将通过在更新进行时锁定要更新的记录来自动处理这个问题(在真正的关系语义中,更新是删除然后重新添加新值——但我怀疑实际的 RDBMS 实现是否专门这样做,但它们必须保证数据操作的原子性)。

无论如何,是的,如果您期望大量用户同时访问您的站点,这可能会对性能产生影响(我正在考虑每秒数千个请求的数量级 - 这里纯属猜想)。从本质上讲,在调用此操作方法时,您正在将原本异步的多线程应用程序转变为同步的单线程应用程序。

换句话说,如果这种设计会对性能产生任何影响,那么这种操作方法几乎肯定会成为瓶颈。

确定性能影响的唯一方法是对您的网站执行负载或压力测试,特别是对于每秒对该方法的数千个(近乎)同时请求。

更新:我看到你有一个名为InsertOrUpdateSecurityroleTypePermission. 您可能应该将此方法/存储过程分成两部分,一是插入,一是更新。这样,正如我之前所说,您可以完全避免潜在的线程/原子性问题。

更新 2: 好的,我想我找到了导致不必要的复杂性的设计决策。相反,您可以使用事务设计一个存储过程,以按照规定的顺序处理必要记录的添加/删除,以完成您的任务。这样,您就可以利用数据库来确保这一切都以原子方式发生;并且使用事务,您可以ROLLBACK在某些情况下一直无效或无法完成(您当前的代码不会这样做),从而使您能够摆脱lock在您的操作方法中。此外,您仍然可以使用 EF——EF 允许您调用在数据库中创建的存储过程。就并发用户而言,使用这种方法,您仍然会遇到“最后一次写入获胜”的情况(例如,顺序“

于 2013-08-21T13:12:19.587 回答