0

在我的应用程序中,多个用户可以编辑数据库中的同一个对象。如果 user1 将数据加载到表单中,但 user2 在 user1 加载表单但在 user1 提交数据之前将数据写入数据库,我想阻止保存 user1 的数据。

Rails 中是否有任何内置的东西,或者 Ruby/Rails 社区库中是否有任何东西可以解决这个问题?

我可以自己尝试,在read_at所有 UI 元素发回的所有模型上都有一个虚拟属性。但我知道问题可能比看起来更复杂,如果有内置的解决方案,我想知道。

除非使用预先构建的解决方案,否则我可能会考虑使用特定于 Rails 的特性吗?我知道有一个表单令牌?我想知道我是否可以从中获取时间信息?

4

2 回答 2

2

Andreas Gebhard 的回答中指向ActiveRecord::Locking::Optimistic的链接从技术上说你需要知道的一切。但是,如果我为您拼写出来,可能会更清楚。

如果您lock_version在表中添加一个名为的字段,默认情况下 ActiveRecord 将启用乐观锁定。但是,您还没有完成。

您遇到的问题称为“丢失的更新问题”,即第二个人的更新破坏了之前个人的更新。如果您所做的只是在数据库层中启用乐观锁定,如果您正常编程并且不采取必要的步骤,您的 Web 应用程序仍然会出现丢失更新问题。

通常,您的更新操作会查找记录,然后将所有字段替换为从表单发送的值。就数据库和 ActiveRecord 所知,您从最近的一条新记录开始并对其进行了更新。因此乐观锁定将满足于允许更新,但您仍然有丢失更新的问题。

您需要做的是将该lock_version字段作为隐藏输入包含在您的表单中。然后当第二个更新的人尝试更新时,将 lock_version 设置为之前更新完成之前的旧值将导致乐观锁定失败。

在悲观锁中,避免丢失更新问题的关键是获取编辑表单必须首先获取锁。如果其他人将其锁定,您将无法编辑。解决丢失更新问题的一个非常重要的关键是循环中的人,通过在编辑之前呈现数据库中的值,这样只有人才能决定更改它们。在丢失的更新中,有人不知道其他人的更新,因此保存了先前的值而不知道它已被更新。

实际上,问题没有解决办法。总会有人输的。在丢失更新问题中,第一个保存的人会失败。在悲观(又名排他锁)中,第二个尝试获得锁的人会失败。在乐观锁定第二个人保存失败。

悲观/排他锁定的缺点是有人试图获取编辑表单被拒绝,因为其他人拥有锁定。此外,锁可能不会在应该释放的时候被释放,并且您可能会遇到死锁。

乐观锁定的缺点是有人可以在编辑时完成所有工作,但在尝试保存时会被拒绝。

无论如何,对于试图编辑的人来说,这都是一个惊喜。丢失更新问题的缺点是最糟糕的情况是惊喜悄然发生,没有人注意到。至少通过排他或乐观锁定,用户会得到通知。使用乐观锁定,他们必须“合并”,可能不得不从新数据开始重做他们的编辑工作。使用独占锁定,他们永远不会遇到这个问题,但他们可能不得不等待并且可能不明白为什么。乐观锁定的普遍偏好是,大多数时候没有更新争用,它只是工作,而对于独占锁定,总是需要进入编辑模式并刷新编辑表单上的数据。

于 2021-05-06T10:53:05.030 回答
0

Rails 为您的问题提供了两种机制:乐观锁定和悲观锁定。就个人而言,我发现乐观的味道更容易使用。网上有很多文档,所以这只是一个起点。它已经涵盖了大多数警告,例如多进程竞争条件和处理它们的隐藏表单字段!

于 2021-05-05T17:53:29.283 回答