2016-04-20 15 views
1

Gibt es eine Möglichkeit, ein Problem zu lösen, wenn Sie eine gleichzeitige Einfügung und Aktualisierung für dasselbe Feld über eine Umgebung mit mehreren Threads erhalten.Gleichzeitiges Einfügen und Aktualisieren Postgres

Beispiel

Thema 1

BEGIN 
insert into users (name,age) values('spiderman',27) 
COMMIT 

Thema 2

BEGIN 
update into users set age = 26 where name='spiderman'; 
COMMIT 

Die meiste Zeit Update (Transaktion) ist der Einsatz nicht bewusst daher Fehler wirft und geschieht.

Was ich hier sehe, ist ein klassisches Beispiel für Rennbedingungen und eine Möglichkeit Rennbedingungen zu vermeiden, ist die Verwendung von Sperren.

Wie Sie Sperren (Datensatz) auf einen Datensatz anwenden, die noch nicht in DB vorhanden sind.

Im obigen Beispiel für eine Anweisung einfügen, so dass Update weiß, dass der Datensatz noch nicht in DB ist.

+0

in einer Web-Umgebung, verwenden Sie https://en.wikipedia.org/wiki/Optimistic_concurrency_control (siehe @Version-Annotation in JPA) –

Antwort

0

Eine Lock-basierte Lösung wäre sehr schwer und wahrscheinlich nicht die Mühe wert. Sie müssen einen Weg finden, um einen Datensatz mit allen möglichen 'Namen'-Feldern zu erstellen, und dann ein Advisory-Lock-System um diese Daten herum erstellen. Es wäre wahrscheinlich auch fehleranfällig.

Wenn jedoch das Problem wirklich, dass die UPDATE wird nicht bis nach der INSERT ausgeführt wird, gibt es einfachere Lösungen.

Insbesondere was den Sinn kommt, ist so etwas wie:

BEGIN; 
    SELECT count(*) FROM users WHERE name = 'spiderman'; 
    -- on the application side, check to see what the result is 
    -- if it's 0, ROLLBACK 
    -- if it's >0: 
    UPDATE users SET age = 26 WHERE name = 'spiderman'; 
COMMIT; 

Wenn Sie wieder rollen am Ende, kommen Sie zurück und versuchen Sie es später noch einmal, ob das etwas einfache Mittel wie sleep für 10 Sekunden und erneut versuchen oder etwas komplizierteres wie das Zurückstellen des Arbeitsgegenstandes in die Warteschlange und das Fortsetzen mit einem anderen Stück Arbeit.

Wenn Sie besorgt sind über Updates zwischen dem SELECT und UPDATE, können Sie SELECT FOR UPDATE, die die ausgewählten Zeilen sperren, bis Ihre Transaktion abgeschlossen ist.

+0

Normalerweise haben wir keine solche Situation, so dass die Einführung von Schlaf fast alle Einfügevorgänge beeinflussen würde. Ich kann nicht auf update auswählen, da die gleichzeitige Operation, die hier passiert, eingefügt und aktualisiert wird. Auswählen ist kein Teil des Abfrageplans. – Viren

+0

Ich dachte an Sperre wie redis.setnx 'Spiderman' – Viren

+0

Eine Möglichkeit, die ich denken kann, ist die Transaktion Isolationsstufe zu diry uncommitted Was haben Sie dazu sagen? – Viren

Verwandte Themen