ActiveRecord的find_or_create*方法是否存在根本缺陷?



有几种方法: first_or_create_byfind_or_create_by,etc et the原理工作:

  1. 与数据库交谈以尝试找到我们想要的东西
  2. 如果我们没有找到它,请自己做
  3. 将其保存到DB

显然,这些方法的并发调用可能没有两个线程找不到他们想要的东西,而在第3步中,人们会意外地失败。

似乎更好的解决方案是 create_or_find

是:

  1. 提前在数据库中创建明智的唯一性约束。
  2. 如果要保存它,请保存一些东西
  3. 如果有效,很好。
  4. 如果由于记录notunique异常而无法工作,它已经存在了,很棒,加载它

因此,在什么情况下,我要使用轨道内置的东西,而不是我自己的(看似更可靠的( create_or_find

挖掘后,我要回答自己的问题。

通过说:

查找或创建的文档

请注意此方法不是原子,它首先运行一个选择,并且 如果没有结果,则尝试插入。如果还有其他 线程或过程都有两个呼叫之间的种族条件 可能是您最终获得两个类似记录的情况。

这是否是一个问题取决于 应用程序,但在特定情况下,行具有唯一的 约束可能会提出例外,只是重试:

begin CreditAccount.find_or_create_by(user_id: user.id) rescue ActiveRecord::RecordNotUnique retry end

通常,这将比create_or_find具有更好的性能。

考虑在成功的情况下,create_or_find将需要1 dB的行程,这只会发生一次。每隔一次,它就需要2 dB旅行(创建失败和搜索(。

在失败的情况下(搜索,创建失败,再次搜索(,RETRIED find_or_create将需要3次旅行,但这只能在一个很小的窗口中发生很多次。除此之外,其他所有呼叫都将需要find_or_create记录,需要1 dB的旅行。

因此,RETRIED find_or_create的摊销成本更好,并快速到达。

显然,默认情况下它不是线程安全,但它们可能会以这种方式设计出更好的方法。

首先找到并在必要时创建比失败的创建更快,有时避免例外(可以处理(。

此讨论可能对您有所帮助。

相关内容

最新更新