Почему MySQL autoincrement увеличивается при неудачных вставках?
Коллега только что сообщил мне об очень странном поведении MySQL.
Предположим, что у вас есть таблица с полем auto_increment и другим полем, которое имеет значение unique (например, поле username). При попытке вставить строку с именем пользователя, которое уже есть в таблице, вставка завершается неудачей, как и ожидалось. Тем не менее значение auto_increment увеличивается, как можно видеть, когда вы вставляете допустимую новую запись после нескольких неудачных попыток.
Например, когда наша последняя запись выглядит так: этот...
ID: 10
Username: myname
...и мы попробуем пять новых записей с тем же значением имени пользователя на нашей следующей вставке мы создадим новую строку так:
ID: 16
Username: mynewname
Хотя это не является большой проблемой само по себе, это кажется очень глупым вектором атаки, чтобы убить таблицу, наводнив ее неудачными запросами вставки, как говорится в справочном руководстве MySQL:
" поведение механизма автоматического приращения не определено, если [...] значение становится больше максимального целого числа, которое может быть хранится в указанном целочисленном типе."
Является ли это ожидаемым поведением?
4 ответов:
InnoDBэто транзакционный двигатель.Это означает, что в следующем сценарии:
Session Aвставляет запись1Session Bвставляет запись2Session Aоткат, существует либо возможность разрыва, либо
session Bбудет блокироваться до тех пор, покаsession Aне совершит или откатится.
InnoDBконструкторы (как и большинство других конструкторов транзакционных двигателей) решили разрешить пробелы.Из документация:
При обращении к счетчику автоинкремента
InnoDBиспользует специальную блокировку уровня таблицыAUTO-INC, которая сохраняется до конца текущего оператораSQL, а не до конца транзакции. Специальная стратегия разблокировки блокировки была введена для улучшения параллелизма вставок в таблицу, содержащую столбецAUTO_INCREMENT...
InnoDBиспользует счетчик автоинкремента в памяти до тех пор, пока сервер работает. Когда сервер находится остановленный и перезапущенный,InnoDBповторно инициализирует счетчик для каждой таблицы для первойINSERTтаблицы, как описано ранее.Если вы боитесь обтекания столбца
id, сделайте егоBIGINT(длиной 8 байт).
Не зная точных внутренних параметров, я бы сказал, что да, автоматическое приращение должно допускать пропущенные значения до вставок сбоя. Допустим, вы выполняете банковскую транзакцию или другую операцию, в которой вся транзакция и несколько записей идут как все или ничего. Если вы попытаетесь вставить, получите идентификатор, а затем отметите все последующие детали этим идентификатором транзакции и вставите подробные записи, вам нужно будет обеспечить свою квалифицированную уникальность. Если у вас есть несколько человек, захлопывающих базу данных, они тоже вам нужно будет убедиться, что они получают свой собственный идентификатор транзакции, чтобы не конфликтовать с вашим, когда их транзакция будет зафиксирована. Если что-то выходит из строя на первой транзакции, никакого вреда не будет, и никаких болтающихся элементов вниз по течению.
Старый пост, но это может помочь людям, Возможно, вам придется установить innodb_autoinc_lock_mode в 0 или 2 .
Системные переменные, принимающие числовое значение, могут быть заданы как--var_name=valueв командной строке или какvar_name=valueв файлах опций.Формат параметров командной строки:
--innodb-autoinc-lock-mode=0Или Откройте консоль MySQL.ini и добавить следующую строку:
innodb_autoinc_lock_mode=0
Я знаю, что это старая статья, но так как я также не мог найти правильный ответ, я действительно нашел способ сделать это. Вы должны обернуть запрос в Оператор if. Его обычно вставить запрос или вставить и на повторяющихся запросов, которые портят организованный порядок автоматического приращения, так что для регулярных вставок использовать:
$check_email_address = //select query here\\ if ( $check_email_address == false ) { your query inside of here }И вместо вставить и на дубликат Используйте a обновить запрос SET WHERE В или вне утверждения if не имеет значения и A заменить в запрос также, кажется, работает
Comments