我有一些 Rails ActiveRecord 代码,如下所示:
new_account_number = Model.maximum(:account_number)
# Some processing that usually involves incrementing
# the new account number by one.
Model.create(foo: 12, bar: 34, account_number: new_account_number)
此代码本身运行良好,但我有一些由 DelayedJob 工作程序处理的后台作业。有两个工作人员,如果他们都开始处理一批处理此代码的作业,他们最终会创建具有相同 account_number 的新 Model
记录,因为找到最大值和创建之间存在延迟一个更高帐号的新记录。
目前,我已经通过在数据库级别向模型表添加唯一性约束来解决此问题,然后通过重新选择最大值来重试,以防此约束触发异常。
然而,这感觉像是一个 hack。
在数据库级别向 account_number
列添加自动递增不是一个选项,因为 account_number 分配需要的不仅仅是递增。
理想情况下,我想锁定有问题的表以供读取,这样在我完成之前,其他人无法对该表执行最大选择查询。但是,我不确定该怎么做。我正在使用 Postgresql。
最佳答案
基于 the ActiveRecord::Locking docs看起来 Rails 没有为表级锁提供内置 API。
但是您仍然可以使用原始 SQL 执行此操作。对于 Postgres,这看起来像
ActiveRecord::Base.transaction do
ActiveRecord::Base.connection.execute('LOCK table_name IN ACCESS EXCLUSIVE MODE')
...
end
锁必须在事务中获取,并在事务结束后自动释放。
请注意,您在此处使用的 SQL 将根据您的数据库而有所不同。
显然锁定整个表并不优雅或高效,但对于小型应用程序,在一段时间内,它可能确实是最好的解决方案。这很简单,也很容易推理。一般来说,建议锁更适合这种数据竞争。
关于sql - Rails ActiveRecord - 如何锁定表以供读取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24587403/