由 find_or_create_by_ 创建的重复记录
我有一个 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。
I have an ActiveRecord object, Corporation, and the only call in my project to create instances of this object looks like:
corp = Corporation.find_or_create_by_eveid_and_user_id(self.corporation_eveid, self.account.user_id)
Yet somehow, after my application has been running happily for a couple of days, there are duplicate records -- record where the eveid and user_id have the same values. How is this possible? Is there something I could be doing wrong in the way I update these records that would cause this problem?
I ended up added a unique, composite index to the table. That should solve the problem, but I don't understand how it's occurring.
This is Rails 3.0.7.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
find_or_create
不执行任何锁定,也不尝试阻止竞争条件。这只是一种方便的方法。如果竞争条件是一个问题,您将需要:编辑|如果您可以在模式级别添加 UNIQUE 约束,如果这是真正的完整性问题,我建议也这样做。
find_or_create
does not perform any locking and makes no attempt to prevent race conditions. It's just a convenience method. If race conditions are a problem, you will need to either:SELECT ... FOR UPDATE
. If you have no reference point to lock on (i.e. no foreign key or anything that already exists in the database), then you'll have to stick with (1).EDIT | If you can add a UNIQUE constraint at the schema level, I'd advise doing so too, if this is a genuine integrity concern.
这在你的种子文件中吗?最好的选择是在模型中编写验证,以防止存在具有相同 eveid 和 user_id 的公司。
在我看来,您使用 find_or_create 播种了此信息,这有效。但也许在当天晚些时候或另一天,有人使用您的 GUI 使用相同的信息创建了另一个。验证可以防止这种情况发生。
我还没有测试过这段代码,但类似的东西可能对你有用。
Is this in your seeds file? Your best bet would be to write validations in your model to prevent the existence of a Corporation with the same eveid and user_id.
It seems to me that you seeded this information using find_or_create, which worked. But then maybe later in the day or another day someone created another one with the same information using your GUI. Validations would prevent this.
I have not tested this code, but something like this may work for you.