2016-08-18 57 views
1

我加載一個shape文件到使用shp2pgsql一個PostGIS的數據庫,通過PSQL管道,包裹在一個python子是這樣的:無法shp2pgsql導入後設置psycopg2自動提交

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聲明,但據我所知ENDCOMMIT是等價的。

然後我想設置con.autocommit = True psycopg2連接到同一個數據庫。我收到以下錯誤:

psycopg2.ProgrammingError: autocommit cannot be used inside a transaction 

爲什麼psycopg2報告事務仍在進行中?有什麼不同的方式我應該關閉psql事務?

如果我不運行shp2pgsql子處理命令,con.autocommit執行成功。默認情況下,shp2pgsql是否將事務打開到某個位置? (http://www.bostongis.com/pgsql2shp_shp2pgsql_quickguide.bqg不建議這樣做)

pg_locks中沒有相關條目存在,表明存在停滯/空閒事務。我不使用shp2pgsql函數中的psycopg2連接對象。而且,如果我的shp2pgsql功能後重新創建一個新的連接對象

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

con.autocommit=True工作正常。

編輯:我當然可以在所有shp2pgsql導入完成後簡單地創建psycopg2連接對象,但這在我的代碼中並不理想,我寧願理解發生了什麼。

編輯2:在打開psycopg2連接後立即設置con.autocommit=True,而不是稍後,繞過此錯誤。

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

我不能看到發生這種情況,但根據thisthisthis,一個事務開始第一次命令發送到數據庫。

交易是每個連接,所以psql不應該讓你絆倒。

跟着this advice,我的建議是你在代碼中的con.autocommit=True之前粘上con.rollback()。這將結束以某種方式開始的隱式事務。如果您仍然擁有您期望的所有數據,則會發出一條SELECT命令或類似的只讀指令。

如果您將con.rollback()con.autocommit=True向後移動,它將允許您在沒有重構代碼的情況下隔離事務已開始的位置。

這是一個猜測,但也許當psql更改數據庫狀態psycopg2在那個時候開始一個事務?我還沒有找到支持這個假設的文件。