确保两个人不会在我的网络应用程序上编辑同一行的最佳方法是啥?

Posted

技术标签:

【中文标题】确保两个人不会在我的网络应用程序上编辑同一行的最佳方法是啥?【英文标题】:What is the best method to make sure two people don't edit the same row on my web app?确保两个人不会在我的网络应用程序上编辑同一行的最佳方法是什么? 【发布时间】:2012-04-05 10:44:52 【问题描述】:

我有一个用于管理数据库的 php/jQuery/AJAX/mysql 应用程序。我想实现防止多个用户同时编辑同一数据库行的功能。

    这叫什么? 我是否使用令牌系统,拥有令牌的人可以在他们释放令牌之前对其进行编辑? 我是否使用“上次编辑日期/时间”来比较您加载 html 表单和数据库中的时间,如果数据库是最近一次编辑,那么它会警告您? 是否使用数据库函数锁定行?

我只是不确定哪个是最好的。假设有 10 - 15 个并发用户

【问题讨论】:

【参考方案1】:

不要试图阻止它。让他们决定在编辑冲突的情况下该怎么做。

向表中添加时间戳。将检索行时的时间戳与当前时间戳进行比较。让他们了解加载和保存之间的变化,并让他们决定采取什么行动。

是的,3 号。

【讨论】:

“最后一胜”是最糟糕的政策之一。 在大多数情况下这很好,但是在他们的关键数据库表上,工作正在从归档和电话更新中,最好提供一种记录锁定机制。否则大多数表我都关闭了该功能。【参考方案2】:

我个人不会阻止这一点。如果这是工作的要求,我会跟踪用户的当前/最后一个已知位置,并禁止某人编辑其他人正在以这种方式编辑的同一行。我已经看到人们在表格中添加一行说 isLocked 或 isBeingWorkedOn 等...但我也看到这种类型的系统也更频繁地失败,或者如果有人在处理它时关闭了卡住的表格等,则需要进行审核才能解锁卡住的表格等。 ..

【讨论】:

【参考方案3】:

有两种通用方法——乐观锁定和悲观锁定。

乐观锁定通常更容易在基于 Web 的环境中实现,因为它基本上是无状态的。它的扩展性也更好。缺点是它假定您的用户通常不会尝试同时编辑同一组行。对于大多数应用程序来说,这是一个非常合理的假设,但您必须验证您的应用程序不是用户经常踩到对方脚趾的异常值之一。在乐观锁定中,您将拥有某种last_modified_timestamp 列,当用户获取数据时您将使用SELECT,然后在您更新日期时在WHERE 子句中使用,即

UPDATE table_name
   SET col1 = <<new value>>,
       col2 = <<new values>>,
       last_modified_timestamp = <<new timestamp>>
 WHERE primary_key = <<key column>>
   AND last_modified_timestamp = <<last modified timestamp you originally queried>>

如果更新 1 行,您就知道您成功了。否则,如果它更新了 0 行,您知道其他人在此期间修改了数据,您可以采取一些措施(通常向用户显示新数据并询问他们是否要覆盖,但您可以采用其他冲突解决方法)。

悲观锁定的实现更具挑战性,尤其是在基于 Web 的应用程序中,尤其是当用户可以在不注销的情况下关闭浏览器,或者用户可能开始编辑一些数据并在点击Submit 之前去吃午饭时。它使扩展变得更加困难,并且通常使应用程序更难以管理。真正值得考虑的是用户是否会定期尝试更新相同的行,或者更新行是否需要用户花费大量时间,因此值得让他们提前知道其他人已锁定该行。

【讨论】:

+1:很好的答案。但没有深入探讨 - 问题在于,使用 optimisitic 锁定很难检测到用户何时访问了记录并且(因此获得了虚拟锁)但随后没有更新记录。 我使用了一个会话变量来存储加载表单的日期时间,并将其与上一次修改的日期时间进行比较,如上所述。非常成功,谢谢。【参考方案4】:

1) 这称为锁定。提到关系数据库(如 MySQL)时,主要有两种锁定类型:表锁定和行锁定。表锁定确保一次只有一个会话对表进行更改,而行锁定确保一次只有一个会话对特定行进行更改。您可以将行锁定视为比表锁定更细粒度的并发访问方法。行锁定更复杂,但允许多个并发会话写入同一个表(如果您的数据库有大量并发写入,这很重要——表锁定应该适合 10-15 个用户) 2-3) MySQL 为您处理并发访问!它在后台自动实现锁定。锁定类型(行或表)取决于您使用的存储引擎。例如,MyISAM 使用表锁定,而 InnoDB 使用行锁定。 MySQL 使用内部表来管理它。您可以通过检查Table_locks_immediateTable_locks_waited 变量(它使用您的选项号2)来查询此表的状态(以及数据库上的所有锁)。 当您在另一个会话正在使用表(或行)时发出 INSERT 或 UPDATE 语句时,调用应用程序(即本例中的 PHP)将暂停几毫秒,直到另一个会话完成写入。

4) 同样,MySQL 会自动处理锁定,但您可以使用LOCK TABLESUNLOCK TABLES 命令手动管理表锁定。如果您在 InnoDB 中使用行锁定,则可以使用许多功能来手动管理并发访问。

有关 MySQL 锁定系统的概述,请参阅 MySQL 的页面 Internal Locking,并参阅 Concurrent Inserts 了解 InnoDB 的行锁定功能。

【讨论】:

此外,OPTIMISTIC 和 PESSIMISTIC 锁定有应用程序样式逻辑...我认为 OP 正在努力解决。 -1:当操作可能跨越多个无状态事务 (HTTP) 时,DBMS 锁定无关紧要。【参考方案5】:

正如其他人所说,处理冲突更新要容易得多。 您的建议称为悲观锁定。之所以称为 thate,是因为两个用户很可能会同时尝试编辑同一条记录。

这是真的吗?

如果用户必须重新开始,那是不是一场灾难,因为他们试图更新的数据被其他人更改了。

锁定成本,你总是锁定在一个悲观的方案中,所以你有一个开销,那是在你开始查看相关数据之前。

让它变得健壮,现在没有人能做到,因为 sumfin' 出了问题......

如果我没有编辑整个文件,需要悲观锁定,我会看看我的设计,因为它不适合目的。

【讨论】:

【参考方案6】:

我打算在我自己的系统中实现这一点。

您可以在记录数据库中创建新列,称为时间锁定。

当打开记录时,您可以将他们打开的记录列的时间锁定设置为当前时间。在编辑记录期间,每 2 分钟通过 ajax 向服务器发送一次 keepalive。当发送keepalive时,服务器会将时间锁定时间增加到当前发送请求的时间,所以第四次(这将在一秒钟内有意义)。当用户完成编辑时,将 timelocked 设置为 false。

现在,如果有人打开已经打开的记录,php 会检查 - 如果 timelocked == false - 意味着它没有被编辑,

否则,记录可能正在被编辑,但如果用户关闭浏览器窗口会怎样。这就是使用keepalive的原因。

如果当前时间和时间锁定的时间差大于 2 分钟,这意味着它们不再是活泼的编辑,这将允许你打开它。

希望你能理解所有这些。

【讨论】:

以上是关于确保两个人不会在我的网络应用程序上编辑同一行的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

使用Bootstrap响应式设计使两个html元素保持在同一行

比较两个日期分区上的同一行

在我的反应组件中实现编辑功能的最佳方法

怎么让两个a标签在同一行左右对齐

确保 cron 作业不会两次执行相同的作业

(C/C++) 在同一行初始化并返回数组