2016-04-06 5 views
-1

Ich fand Arbeit an dem Problem.MySql auto_increment Wert inkorrekt

InnoDB Mit

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 Daten einfügen.

INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected]', 3341234, 0); 
INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected]', 3341234, 0); 
INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected]', 3341234, 0); 
INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected]', 3341234, 0); 

Die UserID von [email protected] 1 ist und die UserID von test2gmail.com 4, nicht 2.

Ich möchte das Ergebnis 2. Was ist die Lösung?

+0

ERSETZEN IN UserAccount VALUES (4, '[email protected], 3341234, 0); – num8er

+0

Wenn Sie bestimmte Zahlen möchten, müssen Sie sie in der SQL-Abfrage eingeben, anstatt "NULL" zu lassen. –

+2

auto_increment funktioniert einfach nicht so. Es garantiert keine fortlaufenden Nummern. – Argeman

Antwort

0

Verwenden Sie in Ihrer Einfügeabfrage IGNORE, bedeutet, dass es keinen doppelten Datensatz einfügt. jedes Mal, wenn Sie gleiche UserID AUTO_INCREMENT Zuwachs und dann verschiedene UserID kommen in einfügen, es Einsatz auto_increment Wert (wie 4 in Ihrem Fall)

INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected], 3341234, 0); -- auto_increment = 1 
INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected], 3341234, 0); -- auto_increment = 2 
INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected], 3341234, 0); -- auto_increment = 3 
INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected], 3341234, 0); -- auto_increment = 4 

Link

3

Das Problem

Der Standard erhöht innodb_autoinc_lock_mode ist "1". Das bedeutet, InnoDB sperrt die Spalte für die automatische Inkrementierung in der Tabelle nur bis zum Ende der INSERT-Anweisung, wenn die Anzahl der einzufügenden Zeilen nicht im Voraus bestimmt werden kann (z. B. in einer Abfrage INSERT ... SELECT). Für eine einfache INSERT wie Ihre Abfragen, weist es die Auto-Inkrement-ID im Voraus zu und erlaubt dann andere Einfügungen in die Tabelle, um schneller zu schreiben.

Im Allgemeinen bedeutet dies, dass die IDs fortlaufend sind, aber wenn Sie INSERT IGNORE verwenden, ist dies eine einfache Einfügung, so dass die ID zugewiesen und dann möglicherweise nicht tatsächlich verwendet wird, da die Zeile ein Duplikat ist.

Ändern der Sperrmodus

Wenn Sie unbedingt eine fortlaufende Kennung für jede Zeile haben müssen, können Sie die InnoDB Autoinkrement-Lock-Modus ändern, indem Sie die folgende Zeile in Ihre my.cnf Hinzufügen und MySQL-Server neu zu starten.

innodb_autoinc_lock_mode = 0 

Es gibt mehr Informationen darüber in der manual. Auch nach dieser Änderung können Lücken in der Sequenz vorhanden sein, wenn die Transaktion, die die IDs generiert, zurückgesetzt wird oder wenn die Zeilen später gelöscht werden. In Ihrem Beispiel lauten die generierten IDs jedoch "1" und "2" wie erwartet.

Auslöser verwendet den gleichen Effekt

zu simulieren, falls Sie nicht my.cnf oder die Lücken nach Roll Rücken ist ein Thema bearbeiten können, können Sie einen Trigger schreiben, anstatt den Primärschlüssel zu aktualisieren. Etwas wie das Folgende funktioniert OK. Es generiert eine Warnung ("Die Spalte 'UserID' darf nicht null sein") für jede Einfügung, fügt sie jedoch erfolgreich mit fortlaufenden IDs ein. Wenn Sie den Benutzer mit der höchsten ID löschen, erhält der nächste Benutzer leider die gleiche ID erneut. Wenn Sie jedoch einen Benutzer in der Mitte der Sequenz löschen, entsteht eine Lücke wie bei der automatischen Erhöhung.

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, '[email protected]', 3341234, 0); 
INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected]', 3341234, 0); 
INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected]', 3341234, 0); 
INSERT IGNORE INTO UserAccount VALUES (NULL, '[email protected]', 3341234, 0); 

müsste ich hinzufügen, ich bin nicht ganz sicher, wie dieser Trigger durchführen würde, wenn Sie viele Einsätze gleichzeitig von mehr als eine Verbindung hergestellt. Also, wenn das ein Problem ist, müssen Sie vielleicht mehr Forschung betreiben.

Verwandte Themen