it-swarm.com.de

Postgres SELECT ... FOR UPDATE in Funktionen

Ich habe zwei Fragen zur Verwendung von SELECT… FOR UPDATE-Sperren auf Zeilenebene in einer Postgres-Funktion:

  • Ist es wichtig, welche Spalten ich auswähle? Haben sie irgendeine Beziehung zu den Daten, die ich sperren und dann aktualisieren muss?

    SELECT * FROM table WHERE x=y FOR UPDATE;
    

    vs

    SELECT 1 FROM table WHERE x=y FOR UPDATE;
    
  • Ich kann in einer Funktion keine Auswahl treffen, ohne die Daten irgendwo zu speichern, also speichere ich sie in einer Dummy-Variablen. Das scheint abgedreht zu sein. Ist es der richtige Weg, Dinge zu tun?

Hier ist meine Funktion:

CREATE OR REPLACE FUNCTION update_message(v_1 INTEGER, v_timestamp INTEGER, v_version INTEGER)
RETURNS void AS $$
DECLARE
    v_timestamp_conv TIMESTAMP;
    dummy INTEGER;
BEGIN
    SELECT timestamp 'Epoch' + v_timestamp * interval '1 second' INTO v_timestamp_conv;
    SELECT 1 INTO dummy FROM my_table WHERE userid=v_1 LIMIT 1 FOR UPDATE;
    UPDATE my_table SET (timestamp) = (v_timestamp_conv) WHERE userid=v_1 AND version < v_version;
END;
$$  LANGUAGE plpgsql;
30
Dan Taylor

Ist es wichtig, welche Spalten ich auswähle?

Nein, das spielt keine Rolle. Selbst wenn SELECT 1 FROM table WHERE ... FOR UPDATE verwendet wird, sperrt die Abfrage alle Zeilen, die den Bedingungen von where entsprechen.

Wenn die Abfrage Zeilen aus einem Join abruft und wir nicht Zeilen aus allen am Join beteiligten Tabellen sperren möchten, sondern nur Zeilen aus bestimmten Tabellen, wird ein SELECT ... FOR UPDATE OF list-of-tablenames Syntax kann nützlich sein:
http://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-FOR-UPDATE-SHARE


Ich kann in einer Funktion keine Auswahl treffen, ohne die Daten irgendwo zu speichern, also speichere ich sie in einer Dummy-Variablen. Das scheint abgedreht zu sein. Ist es der richtige Weg, Dinge zu tun?

Verwenden Sie in Pl/PgSql den Befehl PERFORM, um das Abfrageergebnis zu verwerfen:
http://www.postgresql.org/docs/9.2/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-NORESULT

Anstatt von:

SELECT 1 INTO dummy FROM my_table WHERE userid=v_1 LIMIT 1 FOR UPDATE;

verwenden:

PERFORM 1 FROM my_table WHERE userid=v_1 LIMIT 1 FOR UPDATE;
38
krokodilko