【问题标题】:How can I have rails select for update on multiple rows?如何让 rails select 更新多行?
【发布时间】:2020-01-09 17:06:19
【问题描述】:

我不知道如何在多行上告诉 rails 到 SELECT ... FOR UPDATE。在控制台中闲逛,Foo.where(bar: "baz").lock 确实产生了正确的 SQL。但是当我尝试在事务中执行此操作时,该 ruby​​ 代码实际上并没有生成 SQL。我认为一次性工作是有效的,因为 rails 控制台会自动在关系上运行 .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" = $1 WHERE "foos"."bar = $1 [["bar", "baz2"]]
COMMIT

如果我更改锁定行,以便 rails 认为它​​需要对集合做一些事情,例如在开头添加 puts 或在末尾添加 pluck...

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

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

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

【问题讨论】:

    标签: ruby-on-rails postgresql pessimistic-locking


    【解决方案1】:
    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]
    

    【讨论】:

    • @JohnBachir 这只是示例,块中的操作受SELECT FOR UPDATE 保护。
    • @JohnBachir 可能是我没有得到你最初的问题。你在找什么?
    • 我在 DBA 上问过这个问题:dba.stackexchange.com/questions/257188
    • @JohnBachir UPDATE 将自动锁定记录 - 如第一条评论 @dba.stackexchange 中所述。我的回答是关于“我怎样才能让rails select更新多行”。
    【解决方案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;
    

    【讨论】:

    • 更新 - 我不确定自从我第一次尝试这个之后发生了什么变化,但它要么从来没有工作过,要么因为某种原因在我的项目中停止工作。 YMMV - 评论它是否适合您
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多