web-dev-qa-db-fra.com

Postgres SELECT ... FOR UPDATE dans les fonctions

J'ai deux questions sur l'utilisation de SELECT… FOR UPDATE, le verrouillage au niveau des lignes dans une fonction Postgres:

  • Peu importe les colonnes que je sélectionne? Ont-ils une relation avec les données que je dois verrouiller puis mettre à jour?

    SELECT * FROM table WHERE x=y FOR UPDATE;
    

    contre

    SELECT 1 FROM table WHERE x=y FOR UPDATE;
    
  • Je ne peux pas faire de sélection dans une fonction sans enregistrer les données quelque part, donc j'enregistre dans une variable fictive. Cela semble bizarre; est-ce la bonne façon de faire les choses?

Voici ma fonction:

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

Peu importe les colonnes que je sélectionne?

Non, ça n'a pas d'importance. Même si SELECT 1 FROM table WHERE ... FOR UPDATE est utilisé, la requête verrouille toutes les lignes qui remplissent les conditions.

Si la requête extrait des lignes d'une jointure et que nous ne voulons pas verrouiller les lignes de toutes les tables impliquées dans la jointure, mais uniquement les lignes de tables spécifiques, un SELECT ... FOR UPDATE OF list-of-tablenames la syntaxe peut être utile:
http://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-FOR-UPDATE-SHARE


Je ne peux pas faire de sélection dans une fonction sans enregistrer les données quelque part, donc j'enregistre dans une variable fictive. Cela semble bizarre; est-ce la bonne façon de faire les choses?

Dans Pl/PgSql, utilisez une commande PERFORM pour ignorer le résultat de la requête:
http://www.postgresql.org/docs/9.2/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-NORESULT

Au lieu de:

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

utilisation:

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