Rails 6:当我的模型在验证期间查询多个其他表时,如何处理并发?

Rails 6: How do I deal with concurrency when my model queries several other tables during validation?

我有一个模型 Booking 需要在创建之前针对几个未关联的表进行验证。

像这样:

class Booking < ApplicationRecord
  validate :must_be_available

  private

  def must_be_available
      return if available?

      errors.add :date, 'the booking period is unavailable'
  end

  def available?
    # Queries other tables for staff availability, location availability,
    # opening hours, etc… Also queries bookings table for existing bookings
    ...
  end
end

在验证记录之后但在保存之前,可以在预订或其他表上创建新记录,否则会使新预订无效。也就是说,可能会在不可用期间创建预订。

我读过悲观锁定,但据我了解,我只能锁定特定记录,不能锁定整个表。

这种情况一般是怎么处理的?

做到这一点的简单而规范的方法是在同一事务中使用 REPEATABLE READ 事务隔离级别和 运行 所有查询。这行得通,因为所有查询都将使用相同的 快照 并查看相同的数据库状态,即使并发会话修改数据也是如此。

您付出的代价是,如果并发事务更改了您尝试修改的任何数据,数据修改语句可能会收到 序列化错误。在这种情况下,您必须重复交易。请注意,如果您仅从数据库中读取,则不会发生这种情况。

这种技术(不合逻辑)被命名为乐观锁定