Gibt es eine Möglichkeit, in Postgresql Zeilen auszuwählen, die nicht gesperrt sind? Ich habe eine Multi-Thread-Anwendung, die tun wird:
Select... order by id desc limit 1 for update
auf einem Tisch.
Wenn mehrere Threads diese Abfrage ausführen, versuchen sie beide, dieselbe Zeile zurückzuholen.
Einer erhält die Zeilensperre, der andere blockiert und schlägt dann fehl, nachdem der erste die Zeile aktualisiert hat. Was ich wirklich möchte, ist, dass der zweite Thread die erste Zeile erhält, die mit der WHERE
Klausel und ist nicht bereits gesperrt.
Um zu verdeutlichen, möchte ich, dass jeder Thread sofort die erste verfügbare Zeile aktualisiert, nachdem die Auswahl durchgeführt wurde.
Wenn es also Zeilen gibt mit ID: 1,2,3,4
würde der erste Thread reinkommen, die Zeile mit ID=4
und aktualisieren Sie sie sofort.
Wenn während dieser Transaktion ein zweiter Thread hinzukommt, möchte ich, dass er sich mit ID=3
und aktualisieren Sie diese Zeile sofort.
Denn Share wird das nicht schaffen, auch nicht mit nowait
als die WHERE
Klausel wird mit der gesperrten Zeile übereinstimmen (ID=4 in my example)
. Im Grunde genommen würde ich gerne etwas wie "AND NOT LOCKED" in der WHERE
Klausel.
Users
-----------------------------------------
ID | Name | flags
-----------------------------------------
1 | bob | 0
2 | fred | 1
3 | tom | 0
4 | ed | 0
Wenn die Abfrage lautet " Select ID from users where flags = 0 order by ID desc limit 1
", und wenn eine Zeile zurückgegeben wird, ist das nächste Ding " Update Users set flags = 1 where ID = 0
", dann möchte ich, dass der erste Thread die Zeile mit ID 4
und die nächste, um die Zeile mit ID 3
.
Wenn ich "" anhänge For Update
"an den Select-Thread angehängt wird, erhält der erste Thread die Zeile, der zweite blockiert und gibt nichts zurück, denn sobald die erste Transaktion die WHERE
Klausel nicht mehr erfüllt ist.
Wenn ich nicht " For Update
"Dann muss ich bei der nachfolgenden Aktualisierung eine WHERE-Klausel hinzufügen (WHERE flags = 0), damit nur ein Thread die Zeile aktualisieren kann.
Der zweite Thread wählt die gleiche Zeile aus wie der erste, aber die Aktualisierung des zweiten Threads schlägt fehl.
So oder so kann der zweite Thread keine Zeile erhalten und aktualisieren, weil ich die Datenbank nicht dazu bringen kann, Zeile 4 an den ersten Thread und Zeile 3 an den zweiten Thread zu übergeben, da sich die Transaktionen überschneiden.