我正在使用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
语句,但据我所知END
和COMMIT
是等价的。然后我想为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)
最佳答案
我看不出这是在哪里发生的,但是根据this、this和this,事务在第一次向数据库发送命令时开始。
每个连接都有事务,所以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/