mysql insert race-condition
How do you stop race-Bedingungen in MySQL? das problem bei der hand ist, verursacht durch einen einfachen Algorithmus:
- wählen Sie eine Zeile aus der Tabelle
- wenn es nicht existiert, legen Sie es
und dann entweder erhalten Sie eine doppelte Zeile, oder wenn Sie verhindern, dass es via unique/primary keys, ein Fehler.
Nun normalerweise würde ich denken, Transaktionen Hilfe hier, aber da die Zeile nicht vorhanden ist, wird die Transaktion nicht wirklich helfen (oder bin ich etwas fehlt?).
Sperrtabelle klingt wie ein overkill, vor allem, wenn die Tabelle aktualisiert wird mehrere Male pro Sekunde.
Die einzige andere Lösung, die ich denken kann, ist GET_LOCK() für jede id, aber gibt es nicht einen besseren Weg? Gibt es keine Skalierbarkeit, auch hier? Und auch, tun Sie es für jede Tabelle klingt ein bisschen unnatürlich, wie es klingt wie ein sehr häufiges problem in der high-concurrency-Datenbanken zu mir.
InformationsquelleAutor tpk | 2008-11-05
Du musst angemeldet sein, um einen Kommentar abzugeben.
was Sie wollen, ist LOCK TABLES
oder wenn das übertrieben scheint, wie über INSERT IGNORE mit einem Häkchen, dass die Zeile tatsächlich eingefügt.
Was ist falsch mit nur
INSERT
-ing mit der unique-Einschränkung und abfangen von Fehlern zu sagen: "okay, der Datensatz bereits vorhanden ist."?InformationsquelleAutor Ken
Scheint es mir, sollten Sie einen eindeutigen index für die Spalte "id", also ein wiederholtes einfügen auslösen würde, sondern ein Fehler wird blendend angenommen wieder.
Getan werden kann, dass durch die Definition der id als Primärschlüssel oder mit einem eindeutigen index selbst.
Ich denke, die erste Frage, die Sie stellen müssen, ist, warum haben Sie vielen threads die genau die GLEICHE Arbeit? Warum würden Sie haben, fügen Sie die exakt gleiche Zeile?
Danach beantwortet, ich denke, dass einfach zu ignorieren, die Fehler werden die meisten performante Lösung, aber Messen Sie beide Ansätze (GET_LOCK v/s Fehler ignorieren) und sehen Sie selbst.
Gibt es keine andere Möglichkeit, die ich kenne. Warum willst du Fehler vermeiden? Haben Sie immer noch code für den Fall, wenn eine andere Art von Fehler Auftritt.
Als staticsan sagt, dass Transaktionen nicht helfen, aber, da Sie meist implizit sind, wenn zwei Einsätze sind lief durch die verschiedenen threads, Sie werden beide innerhalb einer impliziten Transaktionen und siehe konsistente Sicht auf die Datenbank.
Das ist, wie soll es funktionieren, bereiten Sie für Transaktionen zu scheitern... in diesem Fall scheint es sehr einfach: Wenn die dup-Taste Fehler ignorieren, da die Zeile bereits vorhanden ist. Ein full table/row sperren kann mehr von einer Leistung getroffen, als einfach nur ignorieren von Fehlern, wenn Sie auftreten. Messen, obwohl
InformationsquelleAutor Vinko Vrsalovic
Sperren der gesamten Tabelle ist in der Tat overkill. Um den Effekt zu erhalten, dass Sie wollen, Sie brauchen etwas, das die Literatur "nennt, Prädikat sperren". Niemand hat jemals gesehen, die außer auf das Papier gedruckt, die wissenschaftlichen Studien, die veröffentlicht werden. Die nächste beste Sache, sind sperren auf die "access paths" auf die Daten (in einigen DBMS ist : "Seite sperren").
Einige nicht-SQL-Systeme ermöglichen es Ihnen, beides zu tun (1) und (2) in einer einzelnen Anweisung mehr oder weniger Sinn der potentielle race-conditions, die sich aus Ihren OS Aussetzung Ihrer Vollstreckung thread Recht zwischen (1) und (2), sind vollständig eliminiert.
Dennoch, in der Abwesenheit von Prädikat sperrt solche Systeme müssen noch greifen, um irgendeine Art von Sperre Schema, und je feiner die "Granularität" (/"scope") der Schlösser, die es dauert, desto besser für die Parallelität.
(Und zum Abschluss : einige DBMS - vor allem diejenigen, die Sie nicht haben zu zahlen für -, in der Tat, bieten keine feinere sperren Granularität als die "gesamte Tabelle".)
InformationsquelleAutor Erwin Smout
Auf eine technische Ebene, eine Transaktion wird hier nicht helfen, da die anderen threads nicht sehen, die neue Zeile, bis Sie einen commit für die Transaktion.
Aber in der Praxis nicht lösen das problem das es nur bewegt. Ihre Anwendung muss nun prüfen, ob das commit schlägt fehl, und entscheiden, was zu tun ist. Ich würde normalerweise haben es rollback, was Sie getan haben, und starten Sie die Transaktion erneut, denn nun wird die Zeile sichtbar sein. Dies ist, wie die Transaktion-basierte programmer funktionieren soll.
InformationsquelleAutor staticsan
Ich lief in das gleiche problem und suchte im Netz nach einem moment 🙂
Schließlich kam ich auf die Lösung ähnlich der Methode zu Erstellung von Dateisystem-Objekten in gemeinsamen (temporären) Verzeichnisse sicher zu öffnen temporäre Dateien:
Scheuen Sie sich nicht busy-loop - Regel wird ausgeführt, einmal oder zweimal.
InformationsquelleAutor xvga
Verhindern Sie doppelte Zeilen sehr einfach, indem Sie eindeutige Indizes auf deinen Tabellen. Das hat nichts zu tun mit SPERREN oder TRANSAKTIONEN.
Haben Sie Sorge, wenn ein insert schlägt fehl, weil es ein Duplikat? Brauchen Sie, um benachrichtigt zu werden, wenn es scheitert? Oder ist alles, was zählt, dass die Zeile eingefügt wurde, und es spielt keine Rolle, durch wen oder wie viele Duplikate einfügt gescheitert?
Wenn man nicht aufpasst, dann alles, was Sie brauchen, ist
INSERT IGNORE
. Es gibt keine Notwendigkeit, denken über Transaktionen oder Tabelle sperren auf alle.InnoDB hat row level locking automatisch, aber das gilt nur für updates und löscht. Sie haben Recht, es gilt nicht für Einlagen. Sie können nicht gesperrt werden, was noch nicht existiert!
Können Sie explizit
LOCK
die gesamte Tabelle. Aber wenn Ihr Zweck ist, zu verhindern, dass Duplikate, dann sind Sie etwas falsch. Wieder, verwenden Sie einen eindeutigen index.Wenn es eine Reihe von änderungen vorgenommen werden und Sie wollen eine alles-oder-nichts-Ergebnis (oder sogar eine Reihe von alle-oder-nichts-Ergebnisse in einem größeren alles-oder-nichts-Ergebnis), dann verwenden Transaktionen und savepoints. Dann nutzen Sie
ROLLBACK
oderROLLBACK TO SAVEPOINT *savepoint_name*
um änderungen rückgängig zu machen, einschließlich Löschungen, updates und Einsätze.LOCK
Tabellen ist kein Ersatz für Geschäfte, aber es ist Ihre einzige option mit MyISAM-Tabellen, die keine Transaktionen unterstützen. Sie können es auch verwenden, mit InnoDB-Tabellen, wenn row-level-Ebene sperren ist nicht genug. Sehen auf dieser Seite für weitere Informationen über die Verwendung von Transaktionen mit lock table-Anweisungen.InformationsquelleAutor Buttle Butkus
Ich habe ein ähnliches Problem. Ich habe eine Tabelle, die unter den meisten Umständen sollte ein einzigartiges ticket_id Wert, aber es gibt einige Fälle, wo ich die Duplikate; nicht das beste design, aber es ist was es ist.
Benutzer B reserviert hat, die Tickets, die Benutzer A meldet zurück, dass das ticket wurde von jemand anderes.
Den Schlüssel in meinem Beispiel ist, dass Sie ein tie-breaker, in meinem Fall ist es die auto-increment-id auf die Reihe.
InformationsquelleAutor SomethingOn