即使由于错误导致插入失败,MySQL 自动增量值也会增加

Posted

技术标签:

【中文标题】即使由于错误导致插入失败,MySQL 自动增量值也会增加【英文标题】:MySQL autoincrement value increases even when insertion fails due to error 【发布时间】:2012-04-23 21:57:12 【问题描述】:

当我从用户那里接收数据时,我每次都会验证输入的格式 (php)。我唯一无法验证(或者我不想)是约束(例如外键)违规。我让 DML 引发错误并让数据库驱动程序引发异常。捕捉到它后,我只是通过 mysql 的错误代码打印出一些错误消息。

问题是,即使插入失败,我看到autoincrement 序列仍在增长,增加。我怎样才能防止这种情况发生?

【问题讨论】:

理想情况下,如果数据无效,您根本不会在 DB 级别触发 INSERT。原因是每当从 DB 序列中选择下一个 ID 时,序列就会自动获得下一个值,即我们看到“自动增量”增长。但这是正确的(和预期的)行为。因此,我建议在访问数据库之前检查/清理您的数据。 (这只是评论而不是答案)。 是否对每个表使用来自 PHP 实体的 SFW 查询进行几个外键约束检查,而不是只访问一次数据库并让它处理违规行为?我的意思是,当您有 5 个约束要检查时,这意味着 5 个 SELECT 并从 PHP 实体进行测试。 (闻起来像我的开销。) 我同意额外查询造成的“开销”。然而,由于它们是 FK(即 ID 字段),它们应该针对索引(通常为 FK 约束/ID 自动创建)运行,在某些情况下(取决于流量/使用情况/索引大小)只是保存在内存中。取决于你的具体情况。就个人而言,当我使用 ORM 时,我会在插入新的/更新的相关实体之前从数据库中获取相关对象(通过 FK,即索引查找),因此不必自己处理序列生成的 ID。 【参考方案1】:

这就是自动递增值和序列的工作方式。使用值时,事务失败不回收,事务回滚。

由于您使用的是自动增量值,因此实际值无关紧要,因此除了缺少数字的美感之外,空格应该不是问题。

【讨论】:

所以没有办法阻止它,你说。正如我最近发现的那样,当存在外键违规时,序列不会发生变化,但是当 INSERT 由于 NOT NULL 错误而失败时,它会发生变化。也许序列在该部分之前发生了变化。想知道,MySQL 如何在 DML 引擎级别评估这些语句。 是的,没有,但是由于自动增量是唯一的并且是递增的,所以您不必担心这一点。我知道当您查看数据时,这些差距看起来很有趣,但它们只是没有意义 自动增量中缺少数字意味着表中容纳最大记录数的容量较小。问题是为什么一个失败的事务不应该触发(隐式)回滚主键值?为什么应该丢失主键值?为什么不恢复到原始状态至少不应该是用户的选择? 然后使用更大的数据值,如果您有太多回滚,那么您的架构和设计中可能存在需要处理的问题 我对我所有的 SQL id/keys 使用无符号 BIGINT...服务器。 :) 即使是未签名的 INT 也非常大...... 4,294,967,295。我认为在数据库需要的不仅仅是未签名的 BIGINT 之前,你和我早就走了。我明白你来自哪里。我看到了我的数据库中的空白,这让我很恼火。我知道发生了什么事,来这里看看你能不能把它关掉......但是,就像每个人所说的......忽略它......只是为你的钥匙使用更大的数字。【参考方案2】:

您可能必须将 innodb_autoinc_lock_mode 设置为 0 或 2。

【讨论】:

【参考方案3】:

我们应该在插入之前检查是否有错误,通过使用存储过程并为每个错误条件创建一个引发应用程序错误,这样当插入散文出现错误时,我们的 auto_increment 永远不会增加。这是因为当存储过程内部发生错误时,您可以设置条件何时可以执行插入过程。当错误帐户设置信号状态 = 1 或其他东西并且当信号状态 == 1 结束时,结束存储过程并且不执行插入 stmt。就是这样。

第二个选项是在发生错误时重置 auto_increment。

ALTER TABLE table_name AUTO_INCREMENT = ?

但是我们需要知道last_id来设置auto_increment,如果你不需要知道last_id值有auto_increment,设置为1,MySQL会设置下一个auto_increment等于记录的最大键+1。

假设在您的数据库中最大 id 为 7,然后您尝试插入两条新记录,但它们都返回错误,然后 auto_increment 将增加并变为 10。 然后你做 ALTER TABLE table_name AUTO_INCREMENT = 1; auto_increment 将回到 8。

这两种方法都是在发生错误时控制 auto_increment 值的方法,当然在应用层插入数据库之前,我们应该在验证步骤中处理它,所以当插入数据库时​​应该没有任何错误,如果我们小心处理的话应用层。

【讨论】:

以上是关于即使由于错误导致插入失败,MySQL 自动增量值也会增加的主要内容,如果未能解决你的问题,请参考以下文章

在插入中立即使用自动增量值

在 MySQL 中,如何在 INSERT 时使用另一列中的自动增量值?

PHP/ACCESS/MYSQL 获取自动增量值并将其添加到另一列,后面有文本

添加自定义自动增量值

如何在 SQLite 的插入查询中返回自动增量值?

SQL - 插入并捕获 id 自动增量值