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

kmb7vmvb  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(99)

在一个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)
qgelzfjb

qgelzfjb1#

Rails中的默认设置是在单个事务中运行测试示例,然后在测试结束时回滚该事务以将数据库恢复到原始状态。这意味着,尽管您创建了所有这些线程,但它们都将从池中汇集到同一个DB连接中,这意味着每个线程中的锁并没有与其他线程隔离。
如果您关闭use_transactional_fixtures,那么您将看到您想要的行为(RSpec::Rails v6有一个用于关闭事务测试的整洁的帮助程序),尽管您还需要自己清理数据库。把这个放在你的测试中:

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

您可能还需要增加database.yml中的连接池大小,以便至少有20个可用连接。

相关问题