MySQL дубликат ID - PullRequest
       7

MySQL дубликат ID

6 голосов
/ 16 марта 2011

Может ли случиться так, что MySQL сгенерирует один и тот же идентификатор автоинкремента дважды?

У нас следующая ситуация:

  1. был создан счет с id = 100;

  2. затем он был удален;

  3. затем был создан другой счет с тем же идентификатором = 100;

Структура таблицы:

CREATE TABLE `bill` (
  `id` int(11) NOT NULL auto_increment,
  `user` int(11) NOT NULL,
  `date` datetime NOT NULL,
  `state` int(11) NOT NULL,
  `adv` bit(1) NOT NULL default b'0',
  `weight` int(11) default NULL,
  PRIMARY KEY  (`id`),
  KEY `FK2E2407EC768806` (`user`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

ALTER TABLE `bill`
  ADD CONSTRAINT `FK2E2407EC768806` FOREIGN KEY (`user`) REFERENCES `user` (`id`);

Может ли быть какое-либо состояние гонки или MySQL гарантирует уникальные идентификаторы автоинкремента?

ОБНОВЛЕНИЕ: мы не можем воспроизвести эту ситуацию, но мы зарегистрировалиэто.

Ответы [ 2 ]

11 голосов
/ 16 марта 2011

Автоинкремент обрабатывается различными механизмами хранения по-разному.Например, в MyISAM следующее значение автоинкремента сохраняется, поэтому при перезапуске сервера MySQL это значение автоинкремента будет сохранено.

Однако InnoDB не сохраняет следующее значение автоинкрементаесли вы перезапустите сервер MySQL, он рассчитает текущее максимальное значение и приращение оттуда.

Это актуально для вас, поскольку вы используете InnoDB.Таким образом, если 100 было максимальным значением идентификатора в вашей таблице, то вы удалили эту строку, а затем перезапустили сервер MySQL, а затем он снова использовал бы 100 при следующей вставке.:

mysql> CREATE TABLE `bill` (
    ->   `id` int(11) NOT NULL auto_increment,
    ->   PRIMARY KEY  (`id`)
    -> ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.12 sec)

mysql> -- start at 99 to force next value to 100
mysql> insert into bill values (99);
Query OK, 1 row affected (0.01 sec)

mysql> -- use auto-increment, should be 100
mysql> insert into bill values (null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from bill;
+-----+
| id  |
+-----+
|  99 |
| 100 |
+-----+
2 rows in set (0.00 sec)

mysql> -- delete max value
mysql> delete from bill where id = 100;
Query OK, 1 row affected (0.00 sec)

mysql> -- use auto-increment, should be 101
mysql> insert into bill values (null);
Query OK, 1 row affected (0.00 sec)

mysql> select * from bill;
+-----+
| id  |
+-----+
|  99 |
| 101 |
+-----+
2 rows in set (0.00 sec)

mysql> -- delete max value
mysql> delete from bill where id = 101;
Query OK, 1 row affected (0.00 sec)

mysql> 
mysql> /*** RESTART MYSQL ***/
mysql> 
mysql> -- use auto-increment, should be 100
mysql> insert into bill values (null);
Query OK, 1 row affected (0.01 sec)

mysql> select * from bill;
+-----+
| id  |
+-----+
|  99 |
| 100 |
+-----+
2 rows in set (0.00 sec)
0 голосов
/ 16 марта 2011

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

...