Python 即使光标已关闭,Psycopg请求也会挂起
我们使用一个对象来保持与PostgreSQL数据库的连接,并创建新的游标来服务请求。我观察到奇怪的行为:即使在读取响应并关闭光标时,请求仍挂起在数据库中,从而阻止更新表等 当连接关闭时,它将消失 我知道ORM框架,也许最终会使用其中的一个,但我只想了解这里发生了什么。为什么请求仍然存在 下面是python代码:Python 即使光标已关闭,Psycopg请求也会挂起,python,postgresql,psycopg2,Python,Postgresql,Psycopg2,我们使用一个对象来保持与PostgreSQL数据库的连接,并创建新的游标来服务请求。我观察到奇怪的行为:即使在读取响应并关闭光标时,请求仍挂起在数据库中,从而阻止更新表等 当连接关闭时,它将消失 我知道ORM框架,也许最终会使用其中的一个,但我只想了解这里发生了什么。为什么请求仍然存在 下面是python代码: import psycopg2 def main(): conn = psycopg2.connect("dbname=tmpdb password=1 host=local
import psycopg2
def main():
conn = psycopg2.connect("dbname=tmpdb password=1 host=localhost")
cur = conn.cursor()
cur.execute("SELECT 1;")
items = cur.fetchall()
cur.close()
#uncommenting the following line solves the problem
#conn.close()
print items
while True:
pass
main()
下面是如何启动代码:
>python test_loop.py
[(1,)]
以下是如何遵守悬挂要求:
tmpdb=# SELECT datname,usename,pid,client_addr,waiting,query_start,query FROM pg_stat_activity ;
datname | usename | pid | client_addr | waiting | query_start | query
---------+----------+-------+-------------+---------+-------------------------------+------------------------------------------------------------------------------------------
tmpdb | savenkov | 530 | ::1 | f | 2013-08-12 13:56:32.652996+00 | SELECT 1;
tmpdb | savenkov | 88351 | | f | 2013-08-12 13:56:35.331442+00 | SELECT datname,usename,pid,client_addr,waiting,query_start,query FROM pg_stat_activity ;
(2 rows)
你认为它为什么会阻塞 创建表
create table t (i integer);
现在运行它:
import psycopg2
def main():
conn = psycopg2.connect("dbname=cpn")
cur = conn.cursor()
cur.execute("SELECT i from t;")
items = cur.fetchall()
print items
raw_input('Enter to insert')
cur.execute("insert into t (i) values (1) returning i;")
items = cur.fetchall()
conn.commit()
cur.execute("SELECT i from t;")
items = cur.fetchall()
print items
raw_input('Enter to update')
cur.execute("update t set i = 2 returning i")
items = cur.fetchall()
conn.commit()
cur.execute("SELECT i from t;")
items = cur.fetchall()
print items
cur.close()
while True:
pass
main()
请注意,您需要提交connection.comit()
尽管如此,不要做连接管理。相反,请使用Pgbouncer之类的连接池。它将使你免于许多复杂和挫折
如果应用程序与数据库在同一台机器上运行,那么就不用麻烦了。只要在必要时经常关闭连接即可。如果两者都在快速的内部网中,那么也不值得增加连接池的复杂性,除非有大量的查询。为什么您认为它会阻塞 创建表
create table t (i integer);
现在运行它:
import psycopg2
def main():
conn = psycopg2.connect("dbname=cpn")
cur = conn.cursor()
cur.execute("SELECT i from t;")
items = cur.fetchall()
print items
raw_input('Enter to insert')
cur.execute("insert into t (i) values (1) returning i;")
items = cur.fetchall()
conn.commit()
cur.execute("SELECT i from t;")
items = cur.fetchall()
print items
raw_input('Enter to update')
cur.execute("update t set i = 2 returning i")
items = cur.fetchall()
conn.commit()
cur.execute("SELECT i from t;")
items = cur.fetchall()
print items
cur.close()
while True:
pass
main()
请注意,您需要提交connection.comit()
尽管如此,不要做连接管理。相反,请使用Pgbouncer之类的连接池。它将使你免于许多复杂和挫折
如果应用程序与数据库在同一台机器上运行,那么就不用麻烦了。只要在必要时经常关闭连接即可。如果两者都在快速的内部网中,那么也不值得增加连接池的复杂性,除非有大量的查询。因此,实际上现在我使用
SELECT 1代码>在任何有意义的请求之后作为一种解决方法,但确实期待这个问题的适当解决方案
在任何有意义的请求之后作为一种解决方法,但确实期待着这个问题的正确解决。@clodaldo neto,您可以使用我上面发布的命令检查请求表中剩下的内容(选择datname、usename、pid、client\u addr、waiting、query\u start、query FROM pg\u stat\u activity;
)。我运行您的脚本,最后一个选择挂起在requests表中。尝试运行脚本,在它获取所有内容并在无限循环中循环后,使“drop table t;”这行不通。至于每次创建和删除连接——这是可行的,但对于(比如)服务于大量请求的API来说就不行了。@savenkov它不是挂起的。您使连接保持打开状态,但它处于空闲状态。执行从pg_stat_activity中选择*并检查每列的含义:。要使拖放有效,您必须发出连接.comit()
@clodaldo neto,谢谢,是的,它是空闲的,我对“挂起”的看法是错误的。酷,我会尝试在每次选择后进行提交,让我们看看它是否解决了问题。有关于提交与关闭空闲请求的关系的文档吗?@savenkov你仍然没有得到它。select不需要提交,只需要修改数据库的命令,如update、insert、delete和ddl命令。您不关闭空闲请求,因为没有空闲请求。有些空闲连接是空闲的,因为您没有关闭它们。如果所有这些对你来说都是陌生的,那么不要,我是认真的,不要管理关系,因为这会伤害你。始终关闭它们,并在必要时使用pgpool。@clodaldo neto,据我所知,空闲连接中的最后一个请求有效地阻止了表的删除。在执行其他请求之后,可以再次删除该表。我看不出你的评论是如何解释这种行为的。@clodaldo neto,你可以使用我在上面发布的命令来检查请求表中剩下的内容(SELECT datname,usename,pid,client\u addr,waiting,query\u start,query FROM pg\u stat\u activity;
)。我运行您的脚本,最后一个选择挂起在requests表中。尝试运行脚本,在它获取所有内容并在无限循环中循环后,使“drop table t;”这行不通。至于每次创建和删除连接——这是可行的,但对于(比如)服务于大量请求的API来说就不行了。@savenkov它不是挂起的。您使连接保持打开状态,但它处于空闲状态。执行从pg_stat_activity中选择*并检查每列的含义:。要使拖放有效,您必须发出连接.comit()
@clodaldo neto,谢谢,是的,它是空闲的,我对“挂起”的看法是错误的。酷,我会尝试在每次选择后进行提交,让我们看看它是否解决了问题。有关于提交与关闭空闲请求的关系的文档吗?@savenkov你仍然没有得到它。select不需要提交,只需要修改数据库的命令,如update、insert、delete和ddl命令。您不关闭空闲请求,因为没有空闲请求。有些空闲连接是空闲的,因为您没有关闭它们。如果所有这些对你来说都是陌生的,那么不要,我是认真的,不要管理关系,因为这会伤害你。始终关闭它们,并在必要时使用pgpool。@clodaldo neto,据我所知,空闲连接中的最后一个请求有效地阻止了表的删除。在执行其他请求之后,可以再次删除该表。我不明白你的评论如何解释这种行为。