3

我正面临锁定asp.net 页面的问题。我们有一个用户个人资料页面,我们需要为首先打开它的用户锁定该页面。详细信息如下,数据库中有许多用户配置文件记录,我们将记录号传递给查询字符串以打开特定页面。用户单击网格中的链接按钮并以只读模式打开记录。有一个编辑按钮,可以启用所有控件,并在用户单击它后使其可供用户使用。任务是将记录锁定给首先单击编辑按钮的用户。

除此之外,还有许多场景,例如用户可能从页面导航,或者他可能会在两者之间关闭页面。在这些情况下,记录应该可供其他用户使用。请给我一些可能的方法或如何解决该场景的示例。

提前致谢

4

7 回答 7

2

由于您提到的所有原因,我认为这是一个非常糟糕的主意,但如果我必须这样做,我会做的是使用 ASP.NET 缓存。

所以,像这样:

    Cache.Add(someUniqueKeyForAUserProfile, theUserThatLockedTheRecord, null, 
    DateTime.Now.AddSeconds(120), Cache.NoSlidingExpiration, CacheItemPriority.Normal, 
    UnlockRecord)

    private static void UnlockRecord(string key, object value, CacheItemRemovedReason reason) {
       //This particular record went longer than 2 minutes without 
       //the user doing anything, do any additional cleanup here you like
    }

然后在页面中您可以执行以下操作:

if (Cache[someUniqueKeyForAUserProfile] != theUserThatLockedTheRecord){
  //Tell the user they can't access the page
}

这里的好处是您使用内置的 ASP.NET 缓存在两分钟后自动“解锁”记录。因此,您可以免费获得所有这些。

于 2011-08-29T01:19:30.673 回答
2

如果您尝试锁定一条记录,您将 100% 获得过时的锁,这意味着您必须有一个过程来移除这些过时的锁。

如果您只是想防止并发修改,您可以使用时间戳或版本字段来执行此操作。编辑记录时,将版本/时间戳放入隐藏字段。然后,当尝试应用更新时,您要做的第一件事是重新读取与 ID 对应的数据,然后检查从数据库返回的版本与隐藏字段中的版本。如果它们匹配,那么继续应用更改是安全的,如果不匹配,那么您可以应用一些逻辑来确定如何继续。

于 2011-08-29T01:24:19.627 回答
2

为了获得良好的用户体验,我会在用户使用一些 javascript 单击“编辑”后在页面上设置心跳。每 5 秒或更合理的时间我会 ping 服务器。因此,如果用户出于某种原因断开连接,您可以通过关闭一个线程来快速释放锁定,该线程检查用户最后一次 ping 页面的时间。您必须将 ping 时间存储在某个地方,例如服务器缓存或会话,但我更喜欢像 memcache 这样的分布式缓存来实现负载平衡(尽管它在您的环境中可能并不重要)。

锁本身应该很容易实现,但我更喜欢像 memcache 这样的分布式缓存解决方案或数据库中的时间戳列。我仍然会包括一个故障安全到期,以防它不会通过心跳到期。

于 2011-08-31T01:33:45.027 回答
1

我曾在一个类似的系统上工作过,在我们的例子中,我们在数据库中的记录上设置了一点,以表明它正在被编辑。但是,与您的情况不同,我们能够设置我们系统的最终用户的期望,即他们必须单击“保存”或“取消”以将位翻转并允许其他用户编辑记录。老实说,我不完全确定如何处理用户放弃页面的情况,但我想到的是有一个运行存储过程的计划任务,如果记录被锁定一段时间,它将释放记录时间(这意味着您还需要一个日期时间字段来指示记录何时被锁定)。

于 2011-08-29T01:17:24.870 回答
1

这是不可能的,因为无法确定用户的浏览器是否已关闭。您可以做一些愚蠢的事情,例如通过让浏览器每分钟轮询您的网站(例如 ping)来推断浏览器已关闭,但我不会走那条路。您也可以在会话上使用 slideExpiration,但对我来说,会话​​应该用于会话而不是“锁定”页面。

也许将页面名称的缓存值保留在缓存中,该缓存记录已锁定文件的用户的记录,有效期为 10 分钟。如果另一个用户请求该文件,您的代码首先检查页面名称是否在缓存中。如果同一个用户请求同一个文件(即回发或刷新)然后更新缓存(即重置计时器),他们将有额外的 10 分钟。假设用户正在写一封冗长的信,但他们还没有回复或刷新页面,并且 10 分钟已到,您可以通过在 9 分钟后触发并提醒用户“您的时间与该页面将在 1 分钟后结束,单击“确定”将您的时间再延长 10 分钟”。

我并不是说这是一个很好的解决方案,但这是一个想法。我所知道的是,由于您无法判断浏览器是否已关闭,因此您需要跳出框框思考。

于 2011-08-31T01:09:22.193 回答
1

@Brian Driscoll 说他们在数据库记录上做了一些设置。然后他们告诉他们的用户他们必须点击保存或取消。真的吗?这有很多问题。

交互设计“用户”的规则 1 永远不会做你所期望的。

锁定东西的规则 1 - 如果负责释放锁的参与者可能失败,它就会失败。即使你通过休克疗法来训练你的用户群,他们的计算机可能会失败,数据库可能会失败,连接可能会失败,网络可能会失败,用户可能会在编辑过程中死去。

锁定东西的规则 2 - 当锁定东西的规则 1 生效时,您需要一个输出 - 特别是 TIMEout 或其他释放孤立锁的方式。

维基百科上有很多关于锁定的文章,值得一读。文件锁定和线程相关的锁定(互斥锁、信号量等)与这个问题非常相似,了解这些工作的原理是一个很好的起点。用户真的只是另一个外部并行处理单元吗?

@Michael Yoon 在我看来给出了一个非常有趣的答案。我们正在实现这种类型的基于页面的锁定,这就是我们现在的系统正在做的事情,但我们将把它改成更像 Yoon 的想法,不断地 ping 服务器以延长锁定。

  1. 用户点击编辑
  2. 请求锁定要编辑的项目(持续时间 5 分钟?)已获得
    • 成功后转到 3
    • 失败时通知未获取用户锁
  3. 检查锁定令牌返回的项目版本
    • 如果版本相同(永远不会更旧,对吗?)转到 5
    • 如果版本较新 GOTO 4
  4. 从服务器检索项目的最新版本
  5. 进入编辑模式
  6. 定期测试锁的年龄,并在锁即将到期时通知用户

具体来说,我们将用 Yoon 的想法替换第 6 项,以免通知打扰用户,而是使用大约 30 秒的“微锁定持续时间”,并通过将来自客户端的锁定持续时间延长超过 30 秒来保持锁定处于活动状态。

于 2011-12-22T18:16:02.217 回答
0

这在网络上是一件很难做到的事情。当 User1 访问数据时,我建议在数据库中使用时间戳。然后给 User1 一种手动解锁页面的方法,并使用 TimeStamp 使用超时值自动解锁 User2 的记录,如果 User1 放弃页面(导航离开,关闭浏览器,失去互联网连接......等) .

于 2011-08-29T01:18:18.000 回答