我有一个ActiveRecord对象,Corporation,我的项目中唯一一个创建该对象实例的调用看起来像:
corp = Corporation.find_or_create_by_eveid_and_user_id(self.corporation_eveid, self.account.user_id)
然而,不知何故,在我的应用程序愉快地运行了几天后,出现了重复的记录——eveid和user_id具有相同值的记录。这怎么可能?我更新这些记录的方式是否有什么错误会导致这个问题?
最后,我在表中添加了一个独特的复合索引。这应该能解决问题,但我不明白它是怎么发生的。
这是Rails 3.0.7。
find_or_create
不执行任何锁定,也不尝试阻止竞争条件。这只是一种方便的方法。如果比赛条件有问题,您需要:
- 使用一个交易,如果你发现别人在你之前写过,就回滚
- (如果您实际预期的是竞争条件,则更好),执行悲观锁定。在这里,您可以从表中选择,首先获取独占锁,然后执行写入并清除锁。在MySQL InnoDB表中,这是
SELECT ... FOR UPDATE
。如果您没有要锁定的参考点(即没有外键或数据库中已经存在的任何东西),那么您将不得不使用(1)
EDIT|如果您可以在模式级别添加UNIQUE约束,如果这是真正的完整性问题,我建议您也这样做。
这在种子文件中吗?最好的办法是在模型中编写验证,以防止存在具有相同eveid和user_id的公司。
在我看来,您使用find_or_create为这些信息播种,这很有效。但是,也许在当天晚些时候或另一天,有人使用您的GUI创建了另一个具有相同信息的。验证可以防止这种情况发生。
我还没有测试过这个代码,但类似的东西可能对你有用。
validates :eveid, :uniqueness => { :scope => :user_id }