一位同事刚刚让我意识到一个非常奇怪的行为.

假设您有一个带有自动递增字段和另一个设置为唯一的字段(例如用户名字段)的表.当试图插入一个用户名已经在表中的行时,插入失败,正如预期的那样.然而,当您在多次try 失败后插入一个有效的新条目时,auto_增量值会增加.

例如,当我们的最后一个条目看起来像这样时...

ID: 10
Username: myname

...我们在下一次插入时try 五个用户名值相同的新条目,我们将创建一个新行,如下所示:

ID: 16
Username: mynewname

虽然这本身不是一个大问题,但它似乎是一个非常愚蠢的攻击向量,它通过用插入失败的请求来淹没表,因为MySQL参考手册指出:

"自动增量机制的行为未定义,如果[…]该值大于可存储在指定整数类型中的最大整数."

这是预期的行为吗?

推荐答案

InnoDB是一个事务引擎.

这意味着在以下场景中:

  1. Session A次插入记录1
  2. Session B次插入记录2
  3. Session A

,要么存在缺口,要么session B将锁定,直到session Apromise 或回滚.

InnoDB名设计师(和大多数其他事务引擎设计师一样) Select 了允许间隙.

documentation人中:

当访问自动递增计数器时,InnoDB使用一个特殊的表级别AUTO-INC锁,它将该锁保留到当前SQL语句的结尾,而不是事务的结尾.引入了特殊的锁释放策略,以提高插入到包含AUTO_INCREMENT列的表中的并发性

只要服务器运行,InnoDB就会使用内存中的自动增量计数器.当服务器停止并重新启动时,InnoDB会重新初始化表的前INSERT个表的计数器,如前所述.

如果您害怕id列环绕,那么将其设为BIGINT(8字节长).

Mysql相关问答推荐

是否有一种方法可以在mysql中设置一列,使其自动成为该行的行号的值?

带负数的MySQL子字符串_索引

在MySQL中存储一条帖子的点赞数量

SQL不断返回查询失败,并且不知道从这里到哪里go

按唯一列排序,但保持匹配的列在一起

如何在 mysql 中获取 Day Wise 的平均值?

SQL使用LIMIT获取结果和结果中的行数

如何从具有第一行列值的表中 Select 客户的最新记录

MySql部分匹配基于部分查询代码

使用 JOIN 计算列中的所有值

MySQL UPDATE 锁会因为连续的 SHARE 锁而饿死吗?

了解 SQL 中的元组语法

MySQL 查询组按日期(12 小时间隔)

如何在 MySQL 上一次删除一系列记录?

按日期和时间降序排序?

如何在 MySQL 的日期时间字段中存储 NULL 值?

MySQL:ALTER IGNORE TABLE 给出违反完整性约束

SQL WHERE 列 = 一切

如何将本地托管的 MySQL 数据库与 docker 容器连接

与 MySql 的连接正在自动中止.如何正确配置Connector/J?