Как предотвратить блокировку таблицы psycopg2

У меня есть таблица на сервере PostgreSQL 9.1:

CREATE TABLE foo(id integer PRIMARY KEY);

В интерактивной оболочке Python с psycopg2 (≥ 2.4.2) я мог бы запустить соединение и курсор и запросить эту таблицу:

import psycopg2
conn = psycopg2.connect('dbname=...')
curs = conn.cursor()
curs.execute('SELECT * FROM foo;')
curs.fetchall()

Однако, если я попытаюсь изменить таблицу:

ALTER TABLE foo ADD COLUMN bar integer;

это запускает виртуальный тупик, пока я не сделаю conn.close() из Python.

Как я могу установить простое соединение с psycopg2, чтобы предотвратить создание взаимоблокировок, вызванных изменениями DDL в другом месте? Соединение в Python может быть только для чтения.


person Mike T    schedule 21.04.2016    source источник


Ответы (2)


Решение, которое я нашел, состоит в том, чтобы использовать set_session следующим образом:

conn.set_session(readonly=True, autocommit=True)

Документация для autocommit предупреждает:

По умолчанию любое выполнение запроса, включая простой SELECT, запускает транзакцию: для долго работающих программ, если не предпринимать никаких дальнейших действий, сессия останется «бездействующей в транзакции», что нежелательно по нескольким причинам (блокировки удерживаются сессия, таблицы раздуваются...). Для долгоживущих скриптов либо завершите транзакцию как можно скорее, либо используйте соединение с автоматической фиксацией.

Это подводит итог опыту с простым SELECT в вопросе.

person Mike T    schedule 29.04.2016
comment
Вы также можете просто сделать conn.commit() вместо установки autocommit на True - person Clodoaldo Neto; 04.05.2016

Так же, как FYI, я столкнулся с той же самой проблемой, делая параллельную запись с psycopg2. В документации указано:

Транзакции обрабатываются классом подключения. По умолчанию при первой отправке команды в базу данных (с использованием одного из курсоров, созданных соединением) создается новая транзакция. Следующие команды базы данных будут выполняться в контексте одной и той же транзакции — не только команды, выданные первым курсором, но и команды, выданные всеми курсорами, созданными одним и тем же соединением. В случае сбоя какой-либо команды транзакция будет прервана, и дальнейшая команда не будет выполняться до тех пор, пока не будет вызван метод rollback().

По сути, psycopg2 блокирует таблицу для всех транзакций, использующих одно и то же соединение.

person Cory Brickner    schedule 05.10.2018
comment
В дополнение к приведенным выше ответам вы также можете предотвратить блокировку таблицы, поставив перед оператором SQL префикс BEGIN; а также заканчивая его END;. Это действительно зависит от масштаба того, что вы пытаетесь сделать. - person Cory Brickner; 08.11.2018