2016-08-18 18 views
1

後psycopg2自動コミットを設定することができませんが、このようなPythonのサブプロセスに包まれ、psqlを介して、パイプ:私はshp2pgsqlとを使用してPostGISのデータベースにシェープファイルをロードしています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文はありませんが、私の知る限りにENDCOMMITは同等です。

同じデータベースへのpsycopg2接続の場合は、con.autocommit = Trueと設定します。

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接続オブジェクトを使用しません。正常に動作con.autocommit=True shp2pgsqlと機能、後、私は新しい接続オブジェクトを再作成する場合

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

編集:すべてのshp2pgsqlのインポートが完了した後ももちろんpsycopg2接続オブジェクトを作成できますが、これは自分のコードでは理想的ではありません。

Edit2: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

私はこれが起こっているが、thisthis、およびthisによると、トランザクションは、コマンドがデータベースに送信される最初の時間を開始している場所を確認することはできません。

トランザクションは接続ごとに行われるため、psqlはあなたをトリップしてはいけません。

this adviceに続いて、コードにcon.autocommit=Trueの直前にcon.rollback()を貼ってください。何らかの形で開始された暗黙的なトランザクションは終了します。まだすべてのデータがある場合は、何かがSELECTコマンドまたは同様の読み取り専用ディレクティブを発行したものよりも優先されます。

con.rollback()con.autocommit=Trueから後方に移動すると、コードの再構成をせずにトランザクションが開始された場所を切り分けることができます。

おそらくpsqlがデータベースの状態を変更すると、psycopg2はその時点でトランザクションを開始しますか?私はこの仮説を支持する文書を見つけていない。

関連する問題