Python 即使光标已关闭,Psycopg请求也会挂起

Python 即使光标已关闭,Psycopg请求也会挂起,python,postgresql,psycopg2,Python,Postgresql,Psycopg2,我们使用一个对象来保持与PostgreSQL数据库的连接,并创建新的游标来服务请求。我观察到奇怪的行为:即使在读取响应并关闭光标时,请求仍挂起在数据库中,从而阻止更新表等 当连接关闭时,它将消失 我知道ORM框架,也许最终会使用其中的一个,但我只想了解这里发生了什么。为什么请求仍然存在 下面是python代码: import psycopg2 def main(): conn = psycopg2.connect("dbname=tmpdb password=1 host=local

我们使用一个对象来保持与PostgreSQL数据库的连接,并创建新的游标来服务请求。我观察到奇怪的行为:即使在读取响应并关闭光标时,请求仍挂起在数据库中,从而阻止更新表等

当连接关闭时,它将消失

我知道ORM框架,也许最终会使用其中的一个,但我只想了解这里发生了什么。为什么请求仍然存在

下面是python代码:

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,据我所知,空闲连接中的最后一个请求有效地阻止了表的删除。在执行其他请求之后,可以再次删除该表。我不明白你的评论如何解释这种行为。