2016-08-18 25 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在那个时候开始一个事务?我还没有找到支持这个假设的文件。