Подтвердить что ты не робот

Postgres SELECT... FOR UPDATE в функциях

У меня есть два вопроса об использовании блокировки уровня SELECT... FOR UPDATE на уровне строк в функции Postgres:

  • Неважно, какие столбцы я выбираю? Имеют ли они какое-либо отношение к тем, какие данные мне нужно заблокировать, а затем обновить?

    SELECT * FROM table WHERE x=y FOR UPDATE;
    

    против

    SELECT 1 FROM table WHERE x=y FOR UPDATE;
    
  • Я не могу сделать выбор в функции, не сохраняя данные где-то, поэтому я сохраняю фиктивную переменную. Это кажется взломанным; это правильный способ сделать что-то?

Вот моя функция:

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;
4b9b3361

Ответ 1

Неважно, какие столбцы я выбираю?

Нет, это не имеет значения. Даже если используется SELECT 1 FROM table WHERE ... FOR UPDATE, запрос блокирует все строки, соответствующие условиям. Если запрос извлекает строки из соединения, и мы не хотим блокировать строки из всех таблиц, участвующих в объединении, но только строки из определенных таблиц, может быть полезно синтаксис SELECT ... FOR UPDATE OF list-of-tablenames:
 http://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-FOR-UPDATE-SHARE


Я не могу сделать выбор в функции, не сохраняя данные где-то, поэтому я сохраняю фиктивную переменную. Это кажется взломанным; это правильный способ сделать что-то?

В Pl/PgSql используйте команду PERFORM для отказа от результата запроса:
http://www.postgresql.org/docs/9.2/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-NORESULT

Вместо:

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

использование:

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