PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

PostgreSQL- und ActiveRecord-Subselect für Race-Condition

Ihre Optionen sind:

  • Führen Sie SERIALIZABLE aus Isolation. Interdependente Transaktionen werden beim Festschreiben abgebrochen, da sie einen Serialisierungsfehler aufweisen. Sie werden viel Fehlerprotokoll-Spam erhalten und viele Wiederholungen unternehmen, aber es wird zuverlässig funktionieren.

  • Definieren Sie einen UNIQUE einschränken und bei einem Fehler erneut versuchen, wie Sie bemerkt haben. Gleiche Probleme wie oben.

  • Wenn es ein übergeordnetes Objekt gibt, können Sie SELECT ... FOR UPDATE das übergeordnete Objekt, bevor Sie Ihr max ausführen Anfrage. In diesem Fall würden Sie SELECT 1 FROM bar WHERE bar_id = $1 FOR UPDATE . Sie verwenden bar als Sperre für alle foo s mit dieser bar_id . Sie können dann sicher sein, dass Sie fortfahren können, solange jede Abfrage, die Ihren Zähler erhöht, dies zuverlässig tut. Das kann ganz gut funktionieren.

    Dies führt immer noch eine aggregierte Abfrage für jeden Aufruf durch, was (für die nächste Option) unnötig ist, aber zumindest nicht das Fehlerprotokoll wie die obigen Optionen spammt.

  • Verwenden Sie einen Tresentisch. Das würde ich tun. Entweder in bar , oder in einer Seitentabelle wie bar_foo_counter , erhalten Sie eine Zeilen-ID mit

    UPDATE bar_foo_counter SET counter = counter + 1
    WHERE bar_id = $1 RETURNING counter
    

    oder die weniger effiziente Option, wenn Ihr Framework RETURNING nicht verarbeiten kann :

    SELECT counter FROM bar_foo_counter
    WHERE bar_id = $1 FOR UPDATE;
    
    UPDATE bar_foo_counter SET counter = $1;
    

    Dann in derselben Transaktion verwenden Sie die generierte Zählerzeile für die number . Beim Festschreiben die Zählertabellenzeile für diese bar_id wird für die nächste zu verwendende Abfrage entsperrt. Bei einem Rollback wird die Änderung verworfen.

Ich empfehle den Counter-Ansatz, indem ich einen dedizierten Seitentisch für den Counter verwende, anstatt eine Spalte zu bar hinzuzufügen . Das ist sauberer zu modellieren und bedeutet, dass Sie weniger Update-Bloat in bar erzeugen , was Abfragen an bar verlangsamen kann .