Это похоже на этот вопрос:
PHP MySQL INSERT терпит неудачу из-за уникального ограничения
но у меня другой поворот. Допустим, у меня есть таблица с одним столбцом. Имя столбца – «title», и на нем есть уникальное ограничение.
Сначала я вставляю строку, где title = "something". В следующий раз, когда я попытаюсь вставить «что-то», он будет терпеть неудачу из-за уникального ограничения ключа (что хорошо). То, что я хотел бы сделать, это позволить ему выйти из строя и проверить код ошибки, предоставленный mysql, чтобы убедиться, что он не удалось из-за уникального ограничения ключа. (т. е. пусть база данных обрабатывает уникальность, и я просто обрабатываю код ошибки и сообщаю пользователю, что заголовок уже существует, когда возвращается результат).
Есть ли способ сделать это?
http://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
http://php.net/manual/en/function.mysql-errno.php
Я должен был сделать это в прошлом, и это не весело:
if( mysql_errno() == 1062) { // Duplicate key } else { // ZOMGFAILURE }
Замечание о стиле программирования (Credits to jensgram из этого ответа)
Вы всегда должны стараться избегать использования магических чисел . Вместо этого вы можете присвоить известному коду ошибки ( 1062
) константе (например, MYSQL_CODE_DUPLICATE_KEY
). Это упростит работу вашего кода, так как условие в выражении if
еще можно прочитать за несколько месяцев, когда значение 1062
исчезло из памяти 🙂
Теперь, когда это 2015 год, есть очень мало причин не использовать PHP-реализацию PDO:
http://php.net/manual/en/book.pdo.php
Правильный, современный метод «OO» для обнаружения и обработки отказа вставки из-за нарушения ограничения ключа выглядит следующим образом:
try { //PDO query execution goes here. } catch (\PDOException $e) { if ($e->errorInfo[1] == 1062) { //The INSERT query failed due to a key constraint violation. } }
В объекте PDOException также есть много чего сказать о специфике ошибки (слишком подробно, чем можно было бы когда-либо хотеть или нужно, по-видимому).
Я считаю, что код ошибки для дубликатов ключей – 1586. Если вы попытались выполнить запрос, а затем, при сбое, проверьте код ошибки с помощью mysql_errno () / mysqli :: errno () и сравните его с 1586, что должно сделать Это. Если это не 1586, проверьте, что это на самом деле, повторив код ошибки после вашего запроса.
Почему бы просто не выбрать сначала, чтобы увидеть, существует ли запись уже. Или полностью устраните ошибку, используя INSERT ON DUPLCATE KEY UPDATE, или даже используйте ключевое слово IGNORE mysql. Почему преднамеренно вызывают ошибку?
Тема представляет интерес для пользователей PHP / Mysql, поэтому позвольте мне изложить решение. пожалуйста, обратите внимание
Предположим, у вас есть форма – где у вас есть поле «Имя»,
Добавьте уникальное ограничение, например –
alter table wb_org add constraint uniq_name unique(name);
Сценарий обработчика формы должен передавать данные на уровень БД, и если есть какие-либо ошибки, уровень БД будет сигнализировать об этом как о DBException (Исключение определено нами). мы переносим код, отправляющий данные на уровень БД в блок try-catch (отображается только соответствующий код)
try{ .... $organizationDao = new \com\indigloo\wb\dao\Organization(); $orgId = $organizationDao->create($loginId,$fvalues["name"]) ; .... } catch(UIException $ex) { .... // do UI exception handling } catch(DBException $ex) { $errors = array(); $code = $ex->getCode(); $message = $ex->getMessage(); // look for code 23000, our constraint name and keyword duplicate // in error message thrown by the DB layer // Util::icontains is just case-insensitive stripos wrapper if( ($code == 23000) && Util::icontains($message,"duplicate") && Util::icontains($message,"uniq_name")) { $errors = array("This name already exists!"); } else { // Not sure? show generic error $errors = array(" Error: doing database operation!") ; } // log errors Logger::getInstance()->error($ex->getMessage()); Logger::getInstance()->backtrace($ex->getTrace()); // store data in session to be shown on form page $gWeb->store(Constants::STICKY_MAP, $fvalues); $gWeb->store(Constants::FORM_ERRORS,$errors); // go back to form $fwd = base64_decode($fUrl); header("Location: " . $fwd); exit(1); }catch(\Exception $ex) { // do generic error handling }
Обратите внимание, что вам нужно найти ex-> getCode () для вашей ситуации. Как и выше, уровень PDO фактически отбрасывает SQLSTATE 23000 как ex-> code (где фактический код ошибки mysql равен 1062). Код также может варьироваться от БД к БД. Такое же сообщение ex-> может также меняться. Было бы лучше обернуть эту проверку в одном месте и скрипку с помощью файла конфигурации.
static function create($loginId, $name) { $dbh = NULL ; try { $dbh = PDOWrapper::getHandle(); //Tx start $dbh->beginTransaction(); ... // do DB operations //Tx end $dbh->commit(); $dbh = null; } catch(\Exception $ex) { $dbh->rollBack(); $dbh = null; throw new DBException($ex->getMessage(),$ex->getCode()); }
Извлечь сообщения об ошибках, установленные в сеансе, и отобразить их в форме.
<?php namespace com\indigloo\exception { class DBException extends \Exception { public function __construct($message,$code=0, \Exception $previous = null) { // PDO exception etc. can return strange string codes // Exception expects an integer error code. settype($code,"integer"); parent::__construct($message,$code,$previous); } } } ?>
static function icontains($haystack, $needle) { return stripos($haystack, $needle) !== false; }
Получить код ошибки и сообщение об ошибке из mysqli и выбросить DBException из уровня DB Обработчик DBException так же.
Я пишу это без какого-либо опыта работы с ним в реальном коде. Поэтому, пожалуйста, дайте мне знать, если вы не согласитесь. Также, пожалуйста, поделитесь, если у вас есть лучшая схема. если вы просто хотите, чтобы у вас был общий тип обработчика, то да.
Проблема, с которой я сталкиваюсь с trigger_error и error_handlers, заключается в том, что
У меня нет большого опыта работы с кодами ошибок (я был поднят на исключениях) – так может быть, кто-то еще может нас просветить.
Образцы кода из моего общедоступного github repo https://github.com/rjha/website – кода, который я пишу, создают создателя веб-сайта для запуска тысяч сайтов из того же БД. Приведенный выше код используется для проверки уникального имени для веб-сайта.
Из документации PHP по функции mysql_errno
:
Returns the error number from the last MySQL function, or 0 (zero) if no error occurred.
Кроме того, из документации MySQL по ошибкам нарушения ограничений код ошибки 893 соответствует:
Constraint violation eg duplicate value in unique index
Итак, мы можем написать что-то подобное, чтобы сделать работу:
if (!$result) { $error_code = mysql_errno(); if ($error_code == 893) { // Duplicate Key } else { // Some other error. } }
Если вы знаете какой-то SQL, попробуйте это решение (протестировано)
$username = "John"; $stmt = $pdo->prepare(" INSERT INTO users ( username ) SELECT * FROM ( SELECT :username ) AS compare WHERE NOT EXISTS ( SELECT username FROM users WHERE username = :username ) LIMIT 1; "); $stmt->bindParam(":username", $username); if ($stmt->execute()) { if ($stmt->rowCount() == 0) { echo "Dublicate Username, ".$username." already exists."; } else { echo $username." not in use yet."; } }