我正在使用shp2pgsql将shapefile加载到postGIS数据库中,该shapefile通过psql进行管道传输,包装在python子进程中,如下所示:

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 subprocess命令,con.autocommit将成功执行。shp2pgsql默认情况下会将事务保留在某个地方吗?(http://www.bostongis.com/pgsql2shp_shp2pgsql_quickguide.bqg不建议这样做)
pg_locks中没有相关条目建议停顿/空闲事务。我不在shp2pgsql函数中使用psycopg2连接对象。如果我重新创建一个新的连接对象
con = psycopg2.connect(host=db_host, user=db_user, password=db_pass, database=db_name)

在shp2pgsql函数之后,con.autocommit=True工作正常。
编辑:当然,在所有shp2pgsql导入完成之后,我可以简单地创建psycopg2连接对象,但这在我的代码中并不理想,我宁愿理解正在发生的事情。
Edit2:在打开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)

最佳答案

我看不出这是在哪里发生的,但是根据thisthisthis,事务在第一次向数据库发送命令时开始。
每个连接都有事务,所以psql不应该让您绊倒。
this advice之后,我的建议是在代码中的con.rollback()之前加上一个con.autocommit=True。这将结束以某种方式启动的隐式事务。如果您仍然拥有所需的所有数据,则会发出SELECT命令或类似的只读指令。
如果您将con.rollback()con.autocommit=True向后移动,它将允许您隔离事务开始的位置,而无需重新构造代码。
这是一个猜测,但也许当psql更改数据库状态时psycopg2会在此时开始一个事务?我还没有找到支持这个假设的医生。

关于python - shp2pgsql导入后无法设置psycopg2自动提交,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39028663/

10-11 01:23