Повторяющиеся записи, созданные find_or_create_by_ - PullRequest
3 голосов
/ 28 мая 2011

У меня есть объект 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 ]

5 голосов
/ 28 мая 2011

find_or_create не выполняет никаких блокировок и не предпринимает попыток предотвратить условия гонки.Это просто удобный метод.Если условия гонки являются проблемой, вам нужно:

  1. Использовать транзакцию и откатиться, если вы обнаружите, что кто-то другой написал прямо перед вами
  2. (Лучше, если вына самом деле ожидая условия гонки), выполнить пессимистическую блокировку.Здесь вы выбираете из таблицы сначала получение эксклюзивной блокировки, затем выполняете запись и снимаете блокировку.В таблицах MySQL InnoDB это SELECT ... FOR UPDATE.Если у вас нет контрольной точки для блокировки (т.е. нет внешнего ключа или чего-либо, что уже существует в базе данных), вам придется придерживаться (1).

EDIT |Если вы можете добавить ограничение UNIQUE на уровне схемы, я бы посоветовал сделать это тоже, если это действительно проблема целостности.

0 голосов
/ 28 мая 2011

Это в вашем файле с семенами? Лучше всего было бы написать валидации в вашей модели, чтобы предотвратить существование корпорации с тем же eveid и user_id.

Мне кажется, что вы загрузили эту информацию с помощью find_or_create, которая сработала. Но потом, может быть, позже в тот же день или в другой день кто-то создал другой с той же информацией, используя ваш графический интерфейс. Проверки предотвратили бы это.

Я не тестировал этот код, но что-то подобное может работать для вас.

validates :eveid, :uniqueness => { :scope => :user_id }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...