MySQL вставка, если не существует, одновременные сеансы - PullRequest
2 голосов
/ 11 декабря 2010

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

Вот моя логика:

if (SELECT COUNT(*) FROM users WHERE nick = :nick) > 0:
    return "name exists";

if (SELECT COUNT(*) FROM users WHERE email = :email) > 0:
    return "email exists";

# OK to insert? Or something bad can happen here?

INSERT INTO users (nick, email) VALUES (:nick, :email)

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

Другая идея состоит в том, чтобы использовать INSERT IGNORE и затем проверять LAST_INSERT_ID (), но всегда ли я могу быть уверен, что LAST_INSERT_ID () == 0, когда вставка пропущена?

Есть ли лучший способ справиться с этим?

Ответы [ 4 ]

3 голосов
/ 11 декабря 2010

Почему бы вам не использовать УНИКАЛЬНЫЙ ИНДЕКС? Просто вставьте новое значение и дайте запросу завершиться ошибкой, если нарушено уникальное ограничение. Немного обработки ошибок поможет.

УНИКАЛЬНОЕ ограничение также решит вашу проблему с одновременными пользователями.

1 голос
/ 11 декабря 2010
INSERT INTO users (nick, email)
SELECT :nick, :email
FROM Dual
WHERE NOT EXISTS (
    SELECT 1
    FROM users
    WHERE nick = :nick OR email =  :email
)

У большинства коннекторов MySql есть способ повлиять на строки, или вы можете SELECT ROW_COUNT().

0 голосов
/ 03 июня 2016

По следующей ссылке нажмите здесь

mysql> LOCK TABLE t WRITE, t AS t1 READ;
mysql> INSERT INTO t SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> INSERT INTO t SELECT * FROM t AS t1;

LOCK TABLE users WRITE, users AS t1 READ;
INSERT INTO users (nick, email)
SELECT :nick, :email
FROM Dual
WHERE NOT EXISTS (
    SELECT *
    FROM users AS t1
    WHERE nick = :nick OR email =  :email
)
UNLOCK TABLES;
0 голосов
/ 11 декабря 2010

Хороший вопрос.

К сожалению, MySQL не поддерживает что-то вроде «вставить в, если не существует».

Есть несколько уродливых решений.

В большинстве случаев лучше всего справиться с этим в вашем приложении. выберите прежде, посмотрите, получите ли вы что-нибудь, вставьте, только если ничего не получили.

затем вы можете поместить уникальный ключ в поля, чтобы обеспечить согласованность базы данных.

Вы также можете напрямую вставлять и полагаться на уникальные ключи. вы получите ошибку, с которой вам придется иметь дело в вашем приложении. Вы МОЖЕТЕ различать ошибки, чтобы вы могли отобразить правильное сообщение. дубликат ключа будет 1062, если я запомню это исправление.

однако есть средства для достижения этой цели другими методами.

тот, о котором я знаю, называется таблицей мьютексов.

это работает так, что вы создаете вторую таблицу "mutex", у которой в качестве рабочей таблицы есть поля ключа syme, которую я теперь называю "table". тогда вы можете сделать что-то вроде:

находится в таблице (field1, field2) select ("input1", "input2") из левой внешней таблицы соединений мьютекса на (mutex.field1 = table.field1 AND mutex.field2 = table.field2) где mutex.field1! = "input1" И mutex.field2! = "field2"

Я не проверял это, и я надеюсь, что я правильно помню tequnique, лучше посмотрите!

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...