2012-05-27 2 views
26

У меня есть таблица MySQL, в которой есть поле для адресов электронной почты, которое определено как уникальное. В этом примере предположим, что вся моя форма позволяет пользователю вставлять свой адрес электронной почты в таблицу.проверить наличие дубликатов и использовать результат PDO errorInfo

Поскольку поле электронной почты уникально, запрос должен быть неудачным, если он пытается дважды ввести один и тот же адрес электронной почты. Мне интересно, какие компромиссы между двумя сценариями:

1) Запустите оперативную инструкцию SELECT перед выполнением вставки. Если выбор возвращает результаты, сообщите об этом пользователю и не запустите оператор INSERT.

2) Запустите INSERT заявление, и проверять наличие дубликата ошибки ввода

// snippet uses PDO 
if (!$prep->execute($values)) 
{ 
    $err = $prep->errorInfo(); 
    if (isset($err[1])) 
    { 
     // 1062 - Duplicate entry 
     if ($err[1] == 1062) 
      echo 'This email already exists.'; 
    } 
} 

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

Кроме того, мне любопытно слышать мысли о стиле кодирования. Мое сердце говорит: «Будь защитником! Проверьте данные перед вставкой! ' в то время как мой мозг говорит: «Хм, возможно, лучше, чтобы MySQL позаботился о проверке данных для вас».

EDIT - Обратите внимание, что это не вопрос «Как это сделать», а вопрос «Почему я должен делать это конкретным образом». Небольшой фрагмент кода, который я включил в работу, но то, что мне интересно, - лучший способ решить проблему.

+2

Вы думаете об использовании 'Exception'? – Leri

+0

В каких отношениях? Конечно, я обрабатываю исключения, но если я не пропущу что-то, обработка исключений выходит за рамки моего вопроса. – JoshBramlett

ответ

8

INSERT + статус проверки должен быть лучшим подходом. С SELECT + INSERT у вас может быть другой поток, вставляющий то же значение между SELECT и INSERT, что означает, что вам нужно будет также обернуть эти два оператора в блокировку таблицы.

В вашей кодировке легко ошибиться на стороне слишком большой защиты. У Python есть высказывание, что «легче просить прощения, чем просить разрешения», и эта философия не является специфичной для Python.

47

Вы могли бы выполнение этого с попыткой поймать блок:

try { 
    $prep->execute($values); 
    // do other things if successfully inserted 
} catch (PDOException $e) { 
    if ($e->errorInfo[1] == 1062) { 
     // duplicate entry, do something else 
    } else { 
     // an error other than duplicate entry occurred 
    } 
} 

Вы также можете посмотреть на альтернативы, такие как «INSERT IGNORE» и «INSERT ... ON KEY UPDATE DUPLICATE» - хотя я думаю, они специфичны для MySQL и будут противоречить переносимости использования PDO, если это вас беспокоит.

Редактировать: Чтобы более формально ответить на ваш вопрос, для меня решение № 1 (защитный программист) в полном объеме эффективно устраняет точку единственного ограничения в первую очередь. Поэтому я бы согласился с вашей мыслью позволить MySQL позаботиться о проверке данных.

+10

'PDOException-> errorInfo [1]' также зависит от MySQL - это код ошибки, специфичный для драйвера, в соответствии с документами PHP. Вам нужно снова проверить 'PDOException-> errorInfo [0]', который является кодом SQLSTATE, который должен быть более или менее (хотя и часто) переносимым. – lanzz

+0

@lanzz не было бы лучше просто проверить результат $ e-> getCode()? –

+0

@aron.duby: Да, но, как и во многих других случаях с катастрофическими документами PHP, метод ['PDOException :: getCode()') (http://bg2.php.net/manual/en/exception.getcode.php) на самом деле полностью недокументированный, и эта функциональность причудливо описана в основных документах класса PDOException, в описании свойства ** protected ** '$ code' (которое было бы полностью недоступным из-за пределов класса PDOException, поэтому никто не мог бы попробуйте найти документацию об этом). – lanzz

Смежные вопросы