有几种方法: first_or_create_by
, find_or_create_by
,etc et the原理工作:
- 与数据库交谈以尝试找到我们想要的东西
- 如果我们没有找到它,请自己做
- 将其保存到DB
显然,这些方法的并发调用可能没有两个线程找不到他们想要的东西,而在第3步中,人们会意外地失败。
似乎更好的解决方案是 create_or_find
是:
- 提前在数据库中创建明智的唯一性约束。
- 如果要保存它,请保存一些东西
- 如果有效,很好。
- 如果由于记录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旅行(创建失败和搜索(。
find_or_create
将需要3次旅行,但这只能在一个很小的窗口中发生很多次。除此之外,其他所有呼叫都将需要find_or_create
记录,需要1 dB的旅行。
因此,RETRIED find_or_create
的摊销成本更好,并快速到达。
显然,默认情况下它不是线程安全,但它们可能会以这种方式设计出更好的方法。
首先找到并在必要时创建比失败的创建更快,有时避免例外(可以处理(。
此讨论可能对您有所帮助。