【问题标题】:MySql auto_increment value incorrectMySql auto_increment 值不正确
【发布时间】:2016-07-26 18:01:12
【问题描述】:

我发现正在解决这个问题。

使用 InnoDB

CREATE TABLE UserAccount ( 
   UserID INT NOT NULL AUTO_INCREMENT,
   Email CHAR(32) NOT NULL UNIQUE,
   Password CHAR(32) NOT NULL,
   Status TINYINT DEFAULT 0,

   PRIMARY KEY(UserID)
);

尝试插入数据。

INSERT IGNORE INTO UserAccount VALUES (NULL, 'test@gmail.com', 3341234, 0);
INSERT IGNORE INTO UserAccount VALUES (NULL, 'test@gmail.com', 3341234, 0);
INSERT IGNORE INTO UserAccount VALUES (NULL, 'test@gmail.com', 3341234, 0);
INSERT IGNORE INTO UserAccount VALUES (NULL, 'test2@gmail.com', 3341234, 0);

test@gmail.com 的UserID 是 1 和 test2gmail.com 的UserID 是 4,而不是 2。

我希望结果是 2。 解决办法是什么?

【问题讨论】:

  • 替换成用户帐户值 (4, 'test2@gmail.com, 3341234, 0);
  • 如果你想要特定的数字,你必须在 SQL 查询中输入它们,而不是让NULL
  • auto_increment 不能那样工作。它不保证连续的数字。
  • 我写了一个innodb差距答案Over Here

标签: mysql auto-increment unique-key


【解决方案1】:

问题

默认innodb_autoinc_lock_mode 是“1”。这意味着如果无法提前确定要插入的行数(例如在 INSERT ... SELECT 查询中),InnoDB 只会锁定表上的自动增量列,直到 INSERT 语句结束。对于像您的查询这样的简单INSERT,它会提前分配自动增量 ID,然后立即允许其他插入到表中,以便更快地写入。

通常这意味着 ID 是连续的,但如果您使用 INSERT IGNORE,这是一个简单的插入,因此 ID 将被分配,然后可能不会实际使用,因为该行是重复的。

更改锁定模式

如果您绝对必须为每一行设置一个连续的标识符,您可以通过将以下行添加到您的 my.cnf 并重新启动您的 MySQL 服务器来更改 InnoDB 自动增量锁定模式。

innodb_autoinc_lock_mode = 0

manual 中有更多相关信息。即使在此更改之后,如果生成 ID 的事务回滚或稍后删除行,序列中也可能存在间隙,但对于您的示例,生成的 ID 如您预期的那样是“1”和“2”。

使用触发器模拟同样的效果

如果您无法编辑您的my.cnf 或回滚后的间隙是一个问题,您可以编写一个触发器来更新主键。像下面这样的工作正常。它为每个插入生成一个警告(“列 'UserID' 不能为空”),但它使用连续的 ID 成功插入。不幸的是,如果您删除具有最高 ID 的用户,下一个用户将再次获得相同的 ID,而如果您在序列中间删除一个用户,则会出现自动增量的间隙。

DROP TABLE UserAccount;

CREATE TABLE UserAccount ( 
   UserID INT NOT NULL,
   Email CHAR(32) NOT NULL UNIQUE,
   Password CHAR(32) NOT NULL,
   Status TINYINT DEFAULT 0,
   PRIMARY KEY(UserID)
);

CREATE TRIGGER UserAccount_before_insert BEFORE INSERT ON UserAccount
FOR EACH ROW SET NEW.UserId = (
    SELECT COALESCE(MAX(UserId), 0) + 1 FROM UserAccount);

INSERT IGNORE INTO UserAccount VALUES (NULL, 'test@gmail.com', 3341234, 0);
INSERT IGNORE INTO UserAccount VALUES (NULL, 'test@gmail.com', 3341234, 0);
INSERT IGNORE INTO UserAccount VALUES (NULL, 'test@gmail.com', 3341234, 0);
INSERT IGNORE INTO UserAccount VALUES (NULL, 'test2@gmail.com', 3341234, 0);

我必须补充一点,如果您从多个连接同时进行大量插入,我不完全确定该触发器将如何执行。因此,如果这是一个问题,您可能需要进行更多研究。

【讨论】:

    【解决方案2】:

    在您的插入查询中使用IGNORE,表示它不会插入重复记录。 每次当您插入相同的 UserID AUTO_INCREMENT 计数增加然后不同的 UserID 进入时,它都会插入递增的 auto_increment 的值(在您的情况下为 4)

    INSERT IGNORE INTO UserAccount VALUES (NULL, 'test@gmail.com, 3341234, 0); -- auto_increment = 1
    INSERT IGNORE INTO UserAccount VALUES (NULL, 'test@gmail.com, 3341234, 0); -- auto_increment = 2
    INSERT IGNORE INTO UserAccount VALUES (NULL, 'test@gmail.com, 3341234, 0); -- auto_increment = 3
    INSERT IGNORE INTO UserAccount VALUES (NULL, 'test2@gmail.com, 3341234, 0); -- auto_increment = 4
    

    Link

    【讨论】:

      猜你喜欢
      • 2016-06-14
      • 2021-05-07
      • 2020-03-21
      • 2021-03-14
      • 2021-11-07
      • 2012-01-05
      相关资源
      最近更新 更多