Проверка наличия существующей записи перед ее созданием все равно выдает ошибку повторяющейся записи - PullRequest
0 голосов
/ 14 сентября 2011

У меня есть таблица со столбцами alias и item_id.Вместе эти 2 поля создают уникальный индекс.

Затем у меня есть некоторый код, который имеет псевдоним и идентификатор элемента и хочет обновить запись для него (илисоздать запись, если она не существует)

//get the current stats for this item
$stats = $model->query(
    'SELECT *, DATEDIFF(NOW(),decayed) as days_since_decay, DATEDIFF(NOW(),created) as days_active
    FROM popularity_views 
    WHERE item_id = '.$query[0][$model->alias]['id'].'
    AND alias = "'.$model->alias.'"'
);
if(empty($stats))
{
    //create new entry
    $insert = $model->query(
        'INSERT INTO popularity_views (item_id, views, alias, created, decayed) 
        VALUES ('.$query[0][$model->alias]['id'].', 1, "'.$model->alias.'", NOW(), NOW())'
    );
}

Каким-то образом этот код вызывается дважды, я не уверен, как.Даже если он вызывается дважды, хотя это не должно иметь значения, потому что, как вы можете видеть, я проверяю, чтобы убедиться, что запись не существует, прежде чем добавлять ее.

Однако при загрузке этой страницы (если запись не существуетперед загрузкой страницы) он дважды пытается создать запись и выдает Ошибка SQL 1062: повторяющаяся запись .Это не имеет смысла для меня.Также, если запись существует до загрузки страницы, она достаточно умна, чтобы вообще не пытаться добавить ее.

Есть идеи?

1 Ответ

3 голосов
/ 14 сентября 2011

Если этот код выполняется в двух отдельных потоках (например, из двух веб-запросов), возможно, у вас есть условие гонки.То есть все происходит в следующем порядке:

  1. Выбор в потоке # 1 выполняется
  2. Выбор в потоке # 2 выполняется
  3. Вставка в потоке # 1 выполняется
  4. Выполнение вставки в потоке # 2 (возвращающая ошибка)

Эту проблему можно решить, заключив последовательность запросов в транзакцию (доступна только с InnoDBтипа таблицы), или используя REPLACE INTO вместо отдельных SELECT и INSERT.

Лично я бы использовал этот последний вариант (REPLACE), поскольку он, вероятно, будет работать лучше, иуменьшает сложность кода, но есть много способов сделать это.

...