Postgres SELECT … FOR UPDATE în funcții (Programare, Postgresql, Plpgsql, Postgresql 9.1, Selectați Pentru Actualizare)

Dan Taylor a intrebat.

Am două întrebări legate de utilizarea SELECT … FOR UPDATE la nivel de rând în cadrul unei funcții Postgres:

  • Contează ce coloane selectez? Au vreo legătură cu datele pe care trebuie să le blochez și apoi să le actualizez?

    SELECT * FROM table WHERE x=y FOR UPDATE;
    

    vs

    SELECT 1 FROM table WHERE x=y FOR UPDATE;
    
  • Nu pot face o selecție într-o funcție fără să salvez datele undeva, așa că le salvez într-o variabilă fictivă. Acest lucru pare a fi o metodă nereușită; este acesta modul corect de a face lucrurile?

Iată funcția mea:

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;

Comentarii

  • Dacă aceasta este într-adevăr funcția ta completă, atunci select .. for update nu servește niciunui scop. UPDATE va bloca rândul la fel de bine. Dacă într-adevăr nu efectuați nicio operațiune între SELECT și UPDATEputeți omite SELECT complet și să vă faceți funcția mai rapidă. –  > Por un_câine_cu_nume_de_câine.
1 răspunsuri
krokodilko

Contează ce coloane selectez?

Nu, nu contează. Chiar dacă SELECT 1 FROM table WHERE ... FOR UPDATE este utilizat, interogarea blochează toate rândurile care îndeplinesc condițiile where.

Dacă interogarea recuperează rânduri dintr-o îmbinare și nu dorim să blocăm rânduri din toate tabelele implicate în îmbinare, ci doar rânduri din anumite tabele, se va utiliza o opțiune SELECT ... FOR UPDATE OF list-of-tablenames poate fi utilă:
http://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-FOR-UPDATE-SHARE

Nu pot face o selecție într-o funcție fără a salva datele undeva, așa că le salvez într-o variabilă fictivă. Acest lucru pare a fi o metodă complicată; este acesta modul corect de a face lucrurile?

În Pl/PgSql folosiți o PERFORM pentru a arunca rezultatul interogării:
http://www.postgresql.org/docs/9.2/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-NORESULT

În loc de:

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

use:

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