2016-08-18 2 views
1

Я загрузка шейпа в базу данных PostGIS с использованием shp2pgsql, по конвейеру через PSQL, завернутый в питоне подпроцесса, как это:Невозможно установить psycopg2 AutoCommit после импорта shp2pgsql

command = "shp2pgsql -s 4269 -a -D -W LATIN1 file.shp table | psql -h host -d db -U user" 
p=subprocess.Popen(command, shell=True) 
p.communicate() 

Это прекрасно работает со следующим выходом :

Loading objects... 
Shapefile type: Polygon 
Postgis type: MULTIPOLYGON[2] 
SET 
SET 
BEGIN 
COMMIT 

Там нет END заявления, но в меру моих знаний END и COMMIT эквивалентны.

Затем я хочу установить con.autocommit = True для подключения psycopg2 к одной базе данных. Я получаю следующую ошибку:

psycopg2.ProgrammingError: autocommit cannot be used inside a transaction 

Почему psycopg2 сообщает, что транзакция все еще продолжается? Есть ли другой способ закрыть транзакцию psql?

Если я не запустил команду subprocess shp2pgsql, con.autocommit будет успешно выполнен. По умолчанию shp2pgsql оставляет транзакцию открытой? (http://www.bostongis.com/pgsql2shp_shp2pgsql_quickguide.bqg не рекомендует это делать)

В pg_locks не существует соответствующих статей, чтобы предлагать сделку с остановкой/бездействием. Я не использую объект соединения psycopg2 в функции shp2pgsql. И, если я воссоздать новый объект подключения

con = psycopg2.connect(host=db_host, user=db_user, password=db_pass, database=db_name) 

после функции shp2pgsql, con.autocommit=True работает отлично.

Редактировать: Я, конечно, могу просто создать объект подключения psycopg2 после завершения импорта shp2pgsql, но это не идеально для моего кода, и я бы лучше понял, что происходит.

Edit2: установка con.autocommit=True сразу после открытия соединения psycopg2, в отличие от более позднего, обходит эту ошибку.

Edit3: добавление MWE

import psycopg2 
import os 
import subprocess 
from glob import glob 

def vacuum(con, table=""): 
    autocommit_orig = con.autocommit 
    con.autocommit = True 
    with con.cursor() as cur: 
     cur.execute("VACUUM ANALYZE {};".format(table)) 
    con.autocommit = autocommit_orig 

def read_shapefile(path, tablename, srid="4269"): 
    command = "shp2pgsql -s {} -a -D -W LATIN1 {} {} | psql -h {} -d {} -U {}".format(srid, path, tablename, host, dbname, user) 
    p=subprocess.Popen(command, shell=True) 
    p.communicate() 

def load_data(con, datapath): 
    dir = os.path.join(datapath,dataname) 
    shapefiles = glob(os.path.join(dir,"*.shp")) 

    for shapefile in shapefiles: 
     read_shapefile(shapefile, tablename) 

if __name__ == "__main__": 
    con = psycopg2.connect(host=db_host, user=db_user, password=db_pass, database=db_name) 
    load_data(con, datapath) 
    vacuum(con, tablename) 
+0

Не могли бы вы разместить MWE для этого? Я хочу быть уверенным, что я понимаю, как излагается код. – Richard

+0

Я добавил MWE выше в исходное сообщение. –

ответ

0

Я не могу видеть, где это происходит, но, по словам this, this и this, транзакция начинается в первый раз, команда отправляется в базу данных.

Сделки за соединение, поэтому psql не следует отключать вас.

Следующее this advice, мое предложение состоит в том, что вы вставляете con.rollback() перед con.autocommit=True в свой код. Это закончит неявную транзакцию, которая как-то началась. Если у вас все еще есть все данные, которые вы ожидаете, чем что-то, выдается команда SELECT или аналогичная директива только для чтения.

Если вы переместите con.rollback() назад от con.autocommit=True, это позволит вам изолировать, где была начата транзакция, без изменения вашего кода.

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

 Смежные вопросы

  • Нет связанных вопросов^_^