【问题标题】:MySQL duplicate IDMySQL重复ID
【发布时间】:2011-07-16 09:04:22
【问题描述】:

会不会发生 MySQL 两次生成相同的自动增量 ID 的情况?

我们有以下情况:

  1. 创建了一个 id=100 的账单;

  2. 然后就被删除了;

  3. 然后创建了另一个账单,它具有相同的 id = 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 是否保证唯一的自动增量 ID?

更新:我们无法重现这种情况,但我们记录了它。

【问题讨论】:

  • 你已经登录了是什么意思?它是否表明这确实发生了?你能告诉我们吗?
  • 账单创建后,在外部支付系统中还创建了另一个具有相同ID的账单,并且该系统显示有两个具有重复ID的账单。
  • 账单的 ID 是否也从支付系统插入到数据库中?因为 MySQL 不应该在自动增量字段上生成重复的 ID - 即使某些 ID 已被删除(除非您截断表)。

标签: mysql auto-increment


【解决方案1】:

不同的存储引擎以不同的方式处理自动增量。例如,使用 MyISAM 会保留下一个自动增量值,这样如果您重新启动 MySQL 服务器,它将保留该自动增量值。

但是,InnoDB 不会保留下一个自动增量值,因此如果您重新启动 MySQL 服务器,它将计算当前最大值并从那里递增。

这与您相关,因为您使用的是 InnoDB。因此,如果 100 是表中的最大 id 值,则删除该行,然后重新启动 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)

【讨论】:

    【解决方案2】:

    也许删除是在事务提交之前完成的?我想在那种情况下,记录永远不会真正更新内部计数器。这有点猜测,但您可以尝试通过将插入、选择和删除语句放在 SQL 脚本中并用事务围绕每对插入、选择和删除来重现它?

    【讨论】:

    • 问题是第一次插入、删除和第二次插入都是在各自的短事务中进行的。
    猜你喜欢
    • 2014-03-08
    • 2012-02-22
    • 2017-07-21
    • 1970-01-01
    • 2011-12-04
    • 2012-01-03
    • 1970-01-01
    • 2015-10-05
    相关资源
    最近更新 更多