2015-04-15 2 views
1

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

Представьте, что вы создаете систему SIGNUP вообще, так что пользователь пытается зарегистрировать и вы сделать что-то вроде этого, чтобы проверить, если их имя пользователя они хотели доступно:

SELECT COUNT(*) FROM users WHERE username='$username'; 

Затем выяснить имя пользователя доступно так что вы идете вперед и сделать это:

INSERT INTO users(username,email) VALUES('$username','$email'); 

Теперь, что происходит, что в очень маловероятно, но возможно, что при какой-либо другой процесс проверки на то же имя пользователя перед тем вы вставили их в ДАТ и они получили одобрение - очевидно, мы не хотим, чтобы в итоге с двумя пользователями с тем же именем мы сделали !?

Так я думал, используя FOR UPDATE замок, чтобы предотвратить это, что-то вроде:

autocommit=0; 
SELECT COUNT(*) FROM users WHERE username='$username" FOR UPDATE; 
INSERT INTO users(username,email) VALUES('$username','$email'); 
commit(); 

Однако я тогда понял, по крайней мере, от того, что я понимаю, что это не будет работать, потому что это только блокирует строки что SELECTнайдено; и поскольку он является COUNT, он не ссылается ни на какие конкретные строки, и даже если вы изменили его на не используя COUNT, он все равно не будет ссылаться ни на какие строки, поскольку имя пользователя не будет найдено.

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

Есть ли лучший способ сделать то, что я хочу сделать, не используя блокировки на уровне таблицы?

ответ

1

Вы можете использовать UNIQUE index на колонке username. Таким образом, если вы попытаетесь сделать INSERT дублирующее значение для username, MySQL будет поддерживать выполнение инструкции и выдавать повторяющуюся ошибку. Ваша программа может уловить эту ошибку (подробности см. В документации вашей клиентской библиотеки) и попросить пользователя использовать другое имя пользователя. Вы можете отличить дублированное имя пользователя от других сообщений об ошибках кодом ошибки, который MySQL возвращает в вашу клиентскую библиотеку.

Также убедитесь, что вы use parameterized queries вместо того, чтобы подставлять строку имени пользователя непосредственно в инструкцию SQL. В противном случае злоумышленники смогут inject arbitrary SQL commands.

+0

Да, я думал об этом, но мне не понравился факт создания общего сообщения об ошибке; но я думаю, что я могу найти определенные ключевые слова в ошибке mysql, чтобы проверить, пытались ли они вставить дублируемое имя пользователя или адрес электронной почты. О, и да, я знаю, чтобы использовать параметризованные запросы, просто сделал это, как это для примера :) – Brett

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