PHP/MySQLi - поймать уникальный конфликт идентификаторов

Мне интересно, есть ли простой способ проверить, вызывает ли оператор INSERT конфликт из-за уникального индекса в поле MySQL при выполнении INSERT.

Например, предположим, что я добавляю пользователя в базу данных, а username — это уникальный индекс:

$sql = new MySQLi(...);
$res = $sql->query('INSERT INTO `users` (`username`) VALUES ("john_galt");');

Пользователь с именем john_galt уже существует, поэтому INSERT выполняться не будет. Но как я могу лучше всего ответить пользователю со значимой ошибкой (т. е. пользователь с таким именем пользователя уже существует; пожалуйста, выберите уникальное имя)?

Я подумал о нескольких вещах, например, проверить, установлен ли insert_id, чего не должно быть, если запрос генерирует ошибку. Но эта ошибка может быть что угодно.

Точно так же я мог бы проверить, не является ли $sql->error пустым, за исключением, опять же, того, что это может быть что угодно — синтаксическая ошибка, неверно отформатированное значение или что-то еще. Очевидно, я не собираюсь распечатывать фактическую ошибку MySQL для конечного пользователя.

Я могу придумать два решения:

  • Перед запуском INSERT запустите SELECT TRUE FROM ``users`` WHERE ``username`` = "john_galt";, чтобы увидеть, существует ли уже имя пользователя в базе данных, но я чувствую, что добавил уникальное ограничение в поле, чтобы мне не пришлось этого делать - в противном случае цель побеждает.
  • strpos($sql->error, 'Duplicate entry') === 0 -- кажется ужасно хакерским.

Есть ли лучший способ определить это с помощью класса PHP MySQLi?


person M Miller    schedule 10.08.2014    source источник
comment
Я предлагаю сначала выполнить проверку, прежде чем пытаться INSERT. Экономит больше времени, чем выполнение ожидаемого отказа. :)   -  person jhnferraris    schedule 10.08.2014
comment
Что ж, это не будет неожиданным сбоем... какой смысл иметь уникальное поле (т.е. помимо первичного индекса), если мне нужно вручную проверять его существование перед вставкой другой строки?   -  person M Miller    schedule 10.08.2014
comment
Я согласен с тем, что в этом смысл уникального поля, и в предварительной проверке нет никакой ценности. В большинстве сценариев допустимая вставка будет гораздо более распространенной, чем коллизия, поэтому более эффективно просто выполнить вставку и отреагировать на состояние ошибки.   -  person xtempore    schedule 24.04.2021


Ответы (1)


Вы можете использовать errno, чтобы получить возвращенный код ошибки и использовать его, например:

if($sql->errno === 1062) {
    //do something
}

Вот список кодов ошибок для MySQL 5.5: http://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html

person StathisG    schedule 10.08.2014
comment
Спасибо! Никогда об этом не думал! Было бы здорово, если бы класс PHP MySQLi включал в себя эти константы, чтобы я не использовал буквальный код ошибки. - person M Miller; 10.08.2014
comment
Не то чтобы мне, вероятно, понадобится получить это конкретное, но возможно ли также извлечь имя поля, если есть несколько полей с уникальным ограничением, и сообщение об ошибке должно быть более конкретным? - person M Miller; 10.08.2014
comment
@MMiller Я не знаю, как это сделать, кроме использования какого-либо регулярного выражения для извлечения имени поля из возвращаемой строки ошибки. Проблема с использованием этого подхода заключается в том, что я думаю, что даже если существует более одного повторяющегося уникального поля, MySQL вернет ошибку только для первого обнаруженного. Кстати, если вам нужно использовать и строку ошибки, и код ошибки, взгляните на error_list, который возвращает всю эту информацию в одном массиве. - person StathisG; 10.08.2014