【问题标题】:Manually updating primary key in a row causes subsequent insert to fail / Duplicate entry for key连续手动更新主键会导致后续插入失败/键的重复条目
【发布时间】:2020-01-13 14:23:19
【问题描述】:

我有一个这样的表:

CREATE TABLE `things` (
  `thing_id` INT(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(32) NOT NULL DEFAULT '',
  PRIMARY KEY (`thing_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4;

还有一些示例数据:

INSERT INTO things VALUES (NULL, 'thing 1'), (NULL, 'thing 2');

在我的应用程序中,有时我想将一行的主键提高到表中的最高值。例如,我希望将thing 1thing_id 更改为3(表的当前自动增量值)。以前该表是 MyISAM,完成如下:

UPDATE things t
    JOIN (SELECT MAX(thing_id) + 1 AS max_id FROM things) v
SET t.thing_id = v.max_id
WHERE thing_id = 1;

那部分仍然有效。但是,现在使用 InnoDB,下一次插入失败,因为执行该更新会使表的自动增量值仍然指向同一事物。所以现在如果我现在像这样插入:

INSERT INTO things VALUES (NULL, 'thing 3');

我会收到如下错误:

键“PRIMARY”的重复条目“3”

这不是 MyISAM 的问题。如何使用 InnoDB 完成同样的事情而不会遇到此错误?我的猜测是有更好的方法来更改thing_id,这将保持表的自动增量值不变,但这就是我难住的地方。

最后,这是一个 dbfiddle: https://www.db-fiddle.com/f/enJPVkwNN6hocjquw38BHD/0

【问题讨论】:

  • 你不应该操纵自动增量主键。如果您告诉我们更多有关您的流程的信息,我们可能会为您提供替代解决方案。
  • 过程是,需要将一行的主键改为表中最高的。此应用程序没有其他选项。目前我最好的想法是复制该行并删除原始行。希望避免这种方法,但 InnoDB 无法应对这种方法是可行的。
  • 提交错误报告:bugs..mysql.com -- UPDATE 未能更新表的最大 AI 值。
  • @RickJames 好像已经是fixed in 8.0
  • @PaulSpiegel - 8.0.0 的变更日志讨论了与 AI 值的新“持续”相关的各种变更。其中一项暗示UPDATE 问题已得到修复(有意或无意)。

标签: mysql primary-key innodb auto-increment


【解决方案1】:

参考:Innodb Auto Increment Initialization

如果您为 InnoDB 表指定 AUTO_INCREMENT 列,则 InnoDB 数据字典中的表句柄包含一个称为自动增量计数器的特殊计数器,用于为该列分配新值。此计数器仅存储在主内存中,而不存储在磁盘上。

更新: 您可以使用以下查询重置此计数器,适用于 MySQL 5.7 中的 InnoDB 存储引擎

ALTER TABLE things AUTO_INCREMENT = 1;

执行此操作会将自动增量计数器重置为 Max + 1 值。

【讨论】:

  • 我不确定如何在生产环境中手动更改表的 AUTO_INCREMENT 值。看起来很危险……
  • @billynoah,mysql 本身在服务器重新启动时使用相同,因为此变量存储在内存中而不是磁盘中。
  • 感谢您的建议,但我认为每次执行此操作时都不断更正表格AUTO_INCREMENT 值感觉不对。我正在寻找一种更清洁的解决方案,并且基于 cmets 似乎升级到修复了此错误的版本将是一个更好的选择。不过,我会为您的时间和精力投赞成票。干杯
  • 那太好了。是的,在 MySQL 8 中,它已被解决,它会自动处理此类升级。它还支持您不能手动将此变量设置为小于表的最大值。
  • 太复杂了。 ALTER TABLE things AUTO_INCREMENT = 1; 应该是 work。但我不是说,我会在生产中这样做。如果无法升级,我宁愿在事务中复制和删除。
猜你喜欢
  • 2019-08-08
  • 1970-01-01
  • 2018-05-26
  • 1970-01-01
  • 2017-05-13
  • 2015-01-24
  • 2011-09-02
  • 2011-10-31
  • 1970-01-01
相关资源
最近更新 更多