由find_or_create_by_创建的重复记录

时间:2011-05-28 17:09:09

标签: ruby-on-rails ruby-on-rails-3 activerecord

我有一个ActiveRecord对象,公司,我的项目中唯一一个创建此对象实例的调用如下:

corp = Corporation.find_or_create_by_eveid_and_user_id(self.corporation_eveid, self.account.user_id)

然而不知何故,在我的应用程序快乐地运行了几天后,有重复的记录 - 记录eveid和user_id具有相同的值。这怎么可能?在我更新这些会导致此问题的记录的方式中,我可能做错了吗?

我最终为表添加了一个唯一的复合索引。这应该可以解决问题,但我不明白它是如何发生的。

这是Rails 3.0.7。

2 个答案:

答案 0 :(得分:5)

find_or_create不会执行任何锁定,也不会尝试阻止竞争条件。这只是一种方便的方法。如果竞争条件有问题,您需要:

  1. 如果您发现其他人已在您之前撰写
  2. ,请使用交易并回滚
  3. (如果你真的期待比赛条件会更好),执行悲观锁定。这是您从表中首先获取独占锁定,然后执行写入并清除锁定的位置。在MySQL InnoDB表中,这是SELECT ... FOR UPDATE。如果您没有锁定参考点(即没有外键或数据库中已存在的任何东西),那么您将不得不坚持使用(1)。
  4. 编辑|如果您可以在架构级别添加UNIQUE约束,我建议也这样做,如果这是一个真正的完整性问题。

答案 1 :(得分:0)

这是你的种子档案吗?您最好的选择是在模型中编写验证,以防止公司与eveid和user_id相同。

在我看来,你使用find_or_create播种了这些信息。但是可能在当天或之后的某天晚些时候,有人使用您的GUI创建了另一个具有相同信息的人。验证会阻止这种情况。

我没有测试过这段代码,但是这样的代码可能适合你。

validates :eveid, :uniqueness => { :scope => :user_id }