【问题标题】:How do you manage concurrent access to forms?您如何管理对表单的并发访问?
【发布时间】:2011-04-03 15:41:21
【问题描述】:

我们的 Web 应用程序中有一组由多名员工管理的表单。这些表格对所有工作人员都是通用的。现在,我们已经实现了一个锁定机制。但问题是没有可靠的方法知道用户何时退出系统,因此需要解锁表单。我想知道是否有更好的方法来管理编辑相同数据的并发用户。

【问题讨论】:

标签: forms web-applications concurrency


【解决方案1】:

最简单的方法是格式化您的更新语句以包含上次更新记录的日期时间。例如:

UPDATE my_table SET my_column = new_val WHERE last_updated = <datetime when record was pulled from the db>

这样,只有在上次读取后没有其他人更改记录时,更新才会成功。

您可以通过在 UPDATE 之后通过 SELECT 检查更新是否成功来向用户发送冲突消息。

【讨论】:

    【解决方案2】:

    您可以在表格上使用“时间戳”列。参考:What is the mysterious 'timestamp' datatype in Sybase?

    我了解您希望避免通过连续更新覆盖现有数据。

    如果是这样,当用户打开屏幕时,您必须向客户端获取最后一个“timestamp”列。

    在更新前更改数据后,您应该检查“时间戳”列(您的和数据库)以确保是否有人在编辑时更改了数据。

    如果它改变了,你会警告一个错误,他必须重新开始。如果不是,请更新数据。时间戳列自动更新。

    【讨论】:

      【解决方案3】:

      我们采用了一个非常简单的乐观锁定方案,其工作原理如下:

      • 每个表都有一个 last_update_date 里面的字段
      • 创建表单时 记录的 last_update_date 存储在隐藏的输入字段中
      • 当表单被发布时,服务器 检查 last_update_date 在 数据库中的日期 隐藏的输入字段。
      • 如果它们匹配, 然后没有其他人改变了 自创建表单以来的记录 系统更新数据。
      • 如果他们不匹配,那么其他人有 更改了记录,因为表格是 创建的。系统将用户返回到表单编辑页面,并告诉用户其他人编辑了记录,他们必须重新应用他们的更改。

      它非常简单,而且效果很好。

      【讨论】:

        【解决方案4】:

        正如 Spence 所建议的,您需要的是乐观并发。一个不考虑数据是否发生变化的标准网站使用我所说的“最后一次写入获胜”。简单地说,无论哪个连接最后保存到数据库,那个版本的数据就是那个版本。在乐观并发中,您使用“第一次写入获胜”逻辑,这样如果两个连接尝试同时保存同一行,则第一个提交获胜,第二个被拒绝。

        这个机制有两个部分:

        1. 第二次提交失败的规则
        2. 系统或用户如何处理被拒绝的提交。

        判断是否拒绝提交

        两种方法:

        1. 每次提交发生时更改的比较列
        2. 将数据与其在数据库中提交的版本进行比较。

        第一个需要使用类似 SQL Server 的 rowversion 数据类型,保证每次行更改时都会更改。好处是它可以很容易地滚动你自己的逻辑来确定是否有变化。当您获取数据时,您提取rowversion 列的值,当您提交时,将该值与数据库中的当前值进行比较。如果它们不同,则自上次检索数据以来数据已更改,您应拒绝提交,否则继续保存数据。

        第二个需要将您提取的列与它们在数据库中的现有提交值进行比较。正如 Spence 建议的那样,如果您尝试更新并且没有更新任何行,那么显然其中一个标准失败了。当某些值为空时,此逻辑可能会变得棘手。许多对象关系映射器,甚至 .NET 的 DataTable 和 DataAdapter 技术都可以帮助您处理这个问题。

        处理被拒绝的提交

        如果您不将其留给用户,那么表单会抛出一些消息,说明自上次编辑后数据已更改,您只需重新检索覆盖其更改的数据即可。可以想象,用户并不特别喜欢这种解决方案,尤其是在可能经常发生的大容量系统中。

        一种更复杂(也更复杂)的方法是向用户展示发生了什么变化,让他们选择尝试重新提交哪些项目,在幕后您将再次检索数据,覆盖由用户与他们的条目并尝试再次提交。在大容量系统中,这仍然会出现问题,因为当用户尝试重新提交时,数据可能已经再次更改。


        结帐概念实际上是用户“锁定”行的悲观并发。正如您所发现的,很难在无状态环境中实现。用户因在签出某些内容时简单地关闭浏览器或使用“后退”按钮返回已签出的集合并尝试重新提交而臭名昭著。 IMO,在基于 Web 的解决方案中尝试这条路线比尝试走这条路更麻烦。假设您编写了最后更改给定行的用户名,使用乐观并发,您可以通知更改被拒绝的用户谁保存了他们之前的数据。

        【讨论】:

          【解决方案5】:

          做一些类似于许多版本控制系统所做的事情。允许任何人编辑数据。当用户提交表单时,会检查数据库是否有更改。如果在此提交之前没有更改记录,则照常允许。如果两个更改相同,则忽略传入的(现在是多余的)更改。

          如果第二次更改与第一次不同,则记录现在存在冲突。向用户呈现一个新表单,该表单指示冲突更新更改了哪些字段。然后,用户有责任解决冲突(通过更新两组更改),或允许现有更新生效。

          【讨论】:

            【解决方案6】:

            您可以使用乐观并发,这是 .Net 数据库的设计方式。实际上,您假设通常没有人会同时编辑一行。发生这种情况时,您可以丢弃所做的更改,或者在有两个用户编辑同一行时尝试创建一些更好的重试逻辑。

            如果您在开始编辑时保留该行中的内容的副本,然后将更新写为:

            Update Table set column = changedvalue 
            where column1 = column1prev 
            AND column2 = column2prev...
            

            如果这更新了零行,那么您知道该行在编辑期间发生了更改,然后您可以处理它,或者只是抛出一个错误并告诉用户重试。

            您还可以创建一些重试逻辑吗?从数据库中重新读取该行并检查您的用户所做的更改和数据库中所做的更改是否能够安全地结合起来,然后自动进行。或者,您可以向用户展示他们是否仍希望根据数据库中现在的值进行更改的选择。

            【讨论】:

            • 你应该改写你的第二句话。乐观并发意味着两个人不能同时编辑同一行是不正确的。这只是意味着在这种情况下,第一次保存获胜,第二次保存被拒绝。
            • 但实际设计基于这样一个事实,即与人们不对同一行执行并发编辑的正常情况相比,此事件很少见。
            【解决方案7】:

            为什么需要查找会话超时?只需同步对您的数据(表单或其他)的访问即可。
            更新:如果您的意思是您有“长事务”,一旦用户打开编辑器(或其他),表单就会被锁定并保持锁定直到用户提交更改,然后:

            • 要么使用乐观锁,要么通过表单数据表的版本控制来实现
            • 乐观锁定会导致工作丢失,如果用户离开很长时间,然后尝试提交他的更改并发现其他人已经更新了表单。在这种情况下,您可能希望实现表单的显式“锁定”,即用户在开始处理表单后立即“锁定”表单。其他用户会注意到表单已“锁定”并与锁定所有者沟通以解决问题,或者他可以为自己“重新锁定”表单,丢失正在处理的第一个用户的所有更新。

            【讨论】:

              【解决方案8】:

              我已经看到了两种方法。第一个是在您的数据库表中有一个与该数据关联的“已签出”列。您的服务必须查找此标志以查看它是否正在被编辑。如果用户未提交更改,您可以在达到时间阈值(使用触发器)后使其过期。第二种方法是有一个专用的“签出”表来存储 id 和对象名称(可能是表名)。从理论上讲,它会以相同的方式工作,并且您的查找时间会更少。但是,我使用第二种方法看到了并发问题。

              【讨论】:

              • 我使用的是第二种方法,有一个专门的表。但问题是结帐不可靠。例如,关闭浏览器并不能可靠地向应用程序注册。
              • 那么,最好的方法是在页面上设置一个心跳来刷新表格中的结帐。如果超过 2 分钟,您将删除结帐。或者您可以让结帐更快地过期。您可以通过一个经常运行的脚本来执行此操作,并删除超过 x 分钟的条目。
              猜你喜欢
              • 2019-06-23
              • 2022-10-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-01-05
              • 1970-01-01
              • 2017-06-11
              • 1970-01-01
              相关资源
              最近更新 更多