简体   繁体   中英

MySql auto_increment value incorrect

I found working on the problem.

Using 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)
);

Try Insert data.

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);

The UserID of test@gmail.com is 1 and the UserID of test2gmail.com is 4, not 2.

I want the result is 2. What's the solution?

The problem

The default innodb_autoinc_lock_mode is "1". This means InnoDB only locks the auto-increment column on the table until the end of the INSERT statement if the number of rows to be inserted cannot be determined in advance (for example in an INSERT ... SELECT query). For a simple INSERT like your queries, it assigns the auto-increment ID in advance and then allows other inserts to the table immediately, for faster writing.

In general this means the IDs are consecutive but if you use INSERT IGNORE this is a simple insert so the ID will be assigned and then potentially not actually used because the row is a duplicate.

Changing the lock mode

If you absolutely must have a consecutive identifier for each row, you can change the InnoDB auto-increment lock mode by adding the following line to your my.cnf and restarting your MySQL server.

innodb_autoinc_lock_mode = 0

There is more information about this in the manual . Even after this change, there may be gaps in the sequence if the transaction that generates the IDs is rolled back or if the rows are deleted later, but for your example the IDs generated are "1" and "2" as you expected.

Using a trigger to simulate the same effect

If you can't edit your my.cnf or the gaps after roll backs is an issue, you could write a trigger to update the primary key instead. Something like the following works OK. It generates a warning ("Column 'UserID' cannot be null") for each insert but it inserts successfully with consecutive IDs. Unfortunately if you delete the user with the highest ID, the next user will get the same ID again, whereas if you delete a user in the middle of the sequence there will be a gap as with auto-increment.

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);

I'd have to add, I'm not completely sure how this trigger would perform if you made lots of inserts concurrently from more than one connection. So if that's an issue you might need to do some more research.

In your insert query use IGNORE , means its not insert duplicate record. every time when you insert same UserID AUTO_INCREMENT count increase and then different UserID come in, it insert incremented auto_increment's value (like 4 in your case)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM