MySql auto_increment值不正确

时间:2016-04-06 11:08:09

标签: mysql auto-increment unique-key

我找到了解决问题的方法。

使用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。 解决方案是什么?

2 个答案:

答案 0 :(得分:3)

问题

默认innodb_autoinc_lock_mode是" 1"。这意味着如果无法事先确定要插入的行数(例如在INSERT查询中),InnoDB仅锁定表上的自动增量列,直到INSERT ... SELECT语句结束。对于像查询这样的简单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);

我必须添加,如果您从多个连接同时进行大量插入操作,我不完全确定此触发器的执行方式。因此,如果这是一个问题,您可能需要做更多的研究。

答案 1 :(得分:0)

在插入查询中使用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