Почему автоинкремент MySQL увеличивается на неудавшихся вставках?

Коллега просто сделал меня знающий об очень странном поведении MySQL.

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

Например, когда наша последняя запись похожа на это...

ID: 10
Username: myname

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

ID: 16
Username: mynewname

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

"Поведение автоинкрементного механизма не определяется, если [...] значение становится больше, чем максимальное целое число, которое может быть сохранено в указанном целом типе".

Это - ожидаемое поведение?

43
задан Sorcy 7 May 2010 в 10:44
поделиться

2 ответа

InnoDB - это транзакционный движок.

Это означает, что в следующем сценарии:

  1. Сессия A вставляет запись 1
  2. Сессия B вставляет запись 2
  3. Сессия A откатывается

, существует либо возможность разрыва, либо сессия B будет блокироваться, пока сессия A не зафиксирует или не откатится.

Разработчики InnoDB (как и большинство других разработчиков транзакционных движков) решили разрешить разрывы.

Из документации:

При доступе к счетчику автоинкремента InnoDB использует специальную блокировку на уровне таблицы AUTO-INC, которая сохраняется до конца текущего SQL оператора, а не до конца транзакции. Специальная стратегия освобождения блокировки была введена для улучшения параллелизма при вставках в таблицу, содержащую AUTO_INCREMENT столбец

...

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

Если вы боитесь, что столбец id обернется вокруг, сделайте его BIGINT (длиной 8 байт).

35
ответ дан 26 November 2019 в 23:08
поделиться

Не зная точного внутреннего устройства, я бы сказал, что да, автоприращение ДОЛЖНО допускать пропуск значений для неудачные вставки. Допустим, вы выполняете банковскую транзакцию или другое, где вся транзакция и несколько записей идут как все или ничего. Если вы попробуете вставить, получите идентификатор, затем отметьте все последующие детали этим идентификатором транзакции и вставьте подробные записи, вам необходимо обеспечить свою квалифицированную уникальность. Если у вас есть несколько человек, хлопающих по базе данных, им тоже нужно будет убедиться, что они получат свой собственный идентификатор транзакции, чтобы не конфликтовать с вашим, когда их транзакция будет зафиксирована. Если что-то не удается в первой транзакции, никакого вреда не будет, и никаких зависших элементов ниже по течению.

5
ответ дан 26 November 2019 в 23:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: