我正在使用带有SQL后端(MySQL或Postgres)的Ruby On Rails(但这并不重要)。
该Web应用程序将是多进程的,并且在同一个DB上运行并运行着一组应用程序服务器进程。

我想知道:有什么好的通用策略来应对赛车条件吗?

由于它将成为一个DB密集型应用程序,因此我可以轻松地看到两个客户端如何尝试同时修改相同的数据。

让我们简化情况:

  • 两个客户端/用户获取相同的数据,这是否同时发生并不重要。
  • 它们带有两个表示相同数据的网页。
  • 后来他们俩都尝试对同一条记录进行一些不兼容的修改。

有没有一种简单的方法来处理这种情况?

我当时正在考虑使用与每个记录关联的id令牌。 记录更新时将更改此令牌,从而使基于陈旧数据的任何后续更新尝试均无效(旧的过期令牌)。

有没有更好的办法? 也许已经在MySQL中内置了某些东西? 我也对这种情况下使用的编码模式感兴趣。

谢谢

===============>>#1 票数:5 已采纳

乐观锁

在webapps中处理此问题的标准方法是使用所谓的“乐观锁定”。

每个记录都有一个唯一的ID和一个整数(或时间戳,但整数更好)乐观锁定字段。 创建记录时,此oplock字段将初始化为0。

当您获得记录时,您将获得oplock字段。

设置记录时,将oplock值设置为用SELECT加1检索到的oplock,并使UPDATE条件是oplock值仍然是上次查看时的值:

UPDATE thetable
SET field1 = ...,
    field2 = ...,
    oplock = 1
WHERE record_id = ...
  AND oplock = 0;

如果您在另一个会话中输了一场比赛,则该语句仍然会成功,但是它将报告受影响的零行。 这样一来,您便可以根据应用程序那部分的含义,告诉用户其更改与另一个用户的更改发生冲突,或者合并他们的更改并重新发送。

许多框架提供工具来帮助实现此目的,大多数ORM都可以立即使用。 Ruby on Rails支持乐观锁定

对于传统应用程序,将乐观锁定与悲观锁定(如下所述)结合使用时要小心。 它可以工作,你只需要添加上一个递增机会锁定列的所有乐观锁定的表触发UPDATE如果UPDATE语句并没有这样做了自我。 为Hibernate oplock支持编写了一个PostgreSQL触发器,该触发器应该很容易适应Rails。 仅当您要从Rails外部更新数据库时才需要这样做,但是在我看来,安全是一个好主意。

悲观锁定

更为传统的方法是在获取要修改的记录时开始事务并执行SELECT ... FOR UPDATE 然后,您可以使事务处于打开状态并处于空闲状态,而用户在考虑要执行的操作,并在COMMIT之前对已锁定的记录发出UPDATE

这不能很好地工作,我不建议这样做。 它要求每个用户进行一个开放的,通常是空闲的事务。 这可能会导致PostgreSQL中MVCC行清理的问题,并可能导致应用程序中的锁定问题。 对于拥有大量用户的大型应用程序,效率也非常低下。

插入种族

INSERT上处理种族要求您在表上拥有合适的应用程序级别的唯一键,因此,当插入冲突时,插入将失败。

  ask by tompave translate from so

未解决问题?本站智能推荐: