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
事务隔离级别和 运行 所有查询。这行得通,因为所有查询都将使用相同的 快照 并查看相同的数据库状态,即使并发会话修改数据也是如此。
您付出的代价是,如果并发事务更改了您尝试修改的任何数据,数据修改语句可能会收到 序列化错误。在这种情况下,您必须重复交易。请注意,如果您仅从数据库中读取,则不会发生这种情况。
这种技术(不合逻辑)被命名为乐观锁定。
我有一个模型 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
事务隔离级别和 运行 所有查询。这行得通,因为所有查询都将使用相同的 快照 并查看相同的数据库状态,即使并发会话修改数据也是如此。
您付出的代价是,如果并发事务更改了您尝试修改的任何数据,数据修改语句可能会收到 序列化错误。在这种情况下,您必须重复交易。请注意,如果您仅从数据库中读取,则不会发生这种情况。
这种技术(不合逻辑)被命名为乐观锁定。