如何让 rails select 更新多行?

How can I have rails select for update on multiple rows?

我不知道如何在多行上告诉 rails 到 SELECT ... FOR UPDATE。在控制台中四处寻找,Foo.where(bar: "baz").lock 确实产生了正确的 SQL。但是当我尝试在事务中执行此操作时,ruby 代码实际上并没有生成 SQL。我认为一次性有效,因为 rails 控制台自动 运行s .all 关系显示结果。

这是我在控制台运行

Foo.transaction do
  Foo.where(bar: "baz").lock  
  Foo.where(bar: "baz").update_all(bar: "baz2")  
end

和 SQL:

BEGIN
  Foo Update All (0.5ms)  UPDATE "foos" SET "bar" =  WHERE "foos"."bar =  [["bar", "baz2"]]
COMMIT

如果我更改锁定行,使 rails 认为它需要对集合做一些事情,比如将 puts 添加到开头或将 pluck 添加到结尾。 .

Foo.where(bar: "baz").lock.pluck(:id)

...然后我确实在更新发生之前得到了预期的 FOR UPDATE 查询,代价是必须通过网络传输结果并将其放入内存,然后什么都不做。

所以似乎 rails 正确地使用 .lock 来修改关系的 SQL,但是没有优雅的方法来实际调用锁。我是在做错什么,还是我们需要使用某种解决方法(例如 pluck)来让查询发生?

ApplicationRecord.transaction do
  User.where(id: [1, 2]).lock!.map do |user|
    puts user.id
    user.id
  end
end

生产

   (0.2ms)  BEGIN
  User Load (0.6ms)  SELECT "users".* FROM "users" WHERE "users"."id" IN (1, 2) FOR UPDATE
1
2
   (0.9ms)  COMMIT
=> [1, 2]

受这里讨论的启发:https://dba.stackexchange.com/questions/257188/

我认为最好的通用解决方案是

Foo.where(bar: "baz").order(:id).lock.pluck('')

哪个会产生

SELECT  FROM "foos" WHERE "foos"."bar" = 'baz' ORDER BY "foos"."id" ASC FOR UPDATE;