Rails 悲观锁定策略在 Rails 7 / Postgresql 应用程序中不起作用

问题描述 投票:0回答:1

在 Rails 7 应用程序中,使用 Postgresql 数据库,我有一个模型

Stat
和 jsonb 字段
data
。我发生了很大的并发,有几个异步进程将在 jsonb 字段中添加自己的行
data

为了测试并发弹性,我创建了一个 Rspec 测试。它将键值对

{"<index>" => "ok"}
添加到
data
jsonb 字段 20 次。最后,我得到数据字段的随机长度。如果它有弹性,长度应始终为“20”。

threads = 20.times.map.with_index do |_, index|
       Thread.new do
             stat = Stat.find(stat_id)
             stat.with_lock do
                   stat.update!(data: stat.data.merge({index => "ok"}))
             end
       end
end
      
threads.map &:join
stat = Stat.find(stat_id)
expect(stat.data.length).to eq(20)
ruby-on-rails ruby postgresql locking
1个回答
0
投票

Rails 中的默认设置是在单个事务中运行测试示例,然后在测试结束时回滚以将数据库恢复到原始状态。这意味着,尽管您创建了所有这些线程,但它们都从池中汇集到同一个数据库连接中,这意味着每个线程中的锁并未与其他线程隔离。

如果您关闭

use_transactional_fixtures
,那么您将看到您想要的行为(RSpec::Rails v6 有一个用于关闭事务测试的简洁助手),尽管您还需要自己清理数据库。将其放入您的测试中:

include RSpec::Rails::FixtureSupport
uses_transaction "the name of your test"
after { Stat.delete_all }

您可能还需要增加

database.yml
中的连接池大小,以便至少有 20 个可用连接。

© www.soinside.com 2019 - 2024. All rights reserved.