确保psycopg2数据库连接保持活动

58
我有一个Python应用程序,它打开一个数据库连接,可以在线挂起几个小时,但有时数据库服务器会重新启动,而Python仍然保持连接,但无法使用“OperationalError”异常。
所以我正在寻找任何可靠的方法来“ping”数据库并知道连接是否正常。我已经查看了psycopg2的文档,但找不到类似的内容。当然,我可以发出一些简单的SQL语句,如“SELECT 1”并捕获异常,但我希望有一种原生的方法,类似于PHP的pg_connection_status
谢谢。
5个回答

81
这个问题很老,但仍然会在谷歌搜索中出现,所以我认为知道 psycopg2.connection 实例现在有一个closed属性是有价值的。当连接处于打开状态时,该属性将为0,并且当连接关闭时,它将大于零。以下示例应该可以说明:
import psycopg2
import subprocess

connection = psycopg2.connect(
    dbname=database,
    user=username,
    password=password,
    host=host,
    port=port
)

print connection.closed # 0

# restart the db externally
subprocess.check_call("sudo /etc/init.d/postgresql restart", shell=True)

# this query will fail because the db is no longer connected
try:
    cur = connection.cursor()
    cur.execute('SELECT 1')
except psycopg2.OperationalError:
    pass

print connection.closed # 2

6
你尝试过关闭数据库连接的TCP句柄吗(在Windows上)。不幸的是,"connection.closed"属性并不会改变其值。 - Vyktor
1
@Vyktor 你说得对!问题在于Python的连接直到尝试与数据库通信时才知道它已经断开。我已经更新了示例。好消息是,你可以将查询执行代码包装起来,在出现错误时检查连接并重新连接。 - Jaymon
我的连接在查询期间关闭,因为数据库重新启动,cur.execute('SELECT 1') 在我这种情况下抛出了一个带有消息 cursor already closed InterfaceError. - raphael
1
connection.closed 2 意味着什么? - Smart Manoj
4
好的,我会尽力进行翻译。根据代码(链接为https://github.com/psycopg/psycopg2/blob/e14e3385b4809ec4223894f8c7a009b1560eb41d/psycopg/connection.h#L95),看起来数字“2”表示发生了一些可怕的事情。 - Jaymon

31

pg_connection_status 通过使用 PQstatus 进行实现。psycopg 并没有暴露该 API,因此该检查不可用。psycopg 仅在建立新连接时和执行开始时调用 PQstatus。所以,是的,你需要发出简单的 SQL 语句来找出连接是否仍然存在。


3
我在阅读psycopg2的源代码时得出了相同的结论。谢谢。 - HardQuestions
2
将请求提交给psycopg作者以添加此功能。 - HardQuestions
1
请查看Jaymon在下面的回答。 - sage88

20

connection.closed 不表示由服务器关闭/切断的连接,它只表示客户端使用 connection.close() 关闭的连接。

要确保连接仍然有效,请读取属性 connection.isolation_level。如果连接已断开,则这将引发一个带有 pgcode == "57P01" 的 OperationalError。

这会增加与数据库的往返延迟,但应该优于 SELECT 1 或类似操作。

import psycopg2
dsn = "dbname=postgres"
conn = psycopg2.connect(dsn)

# ... some time elapses, e.g. connection within a connection pool

try:
    connection.isolation_level
except OperationalError as oe:
    conn = psycopg2.connect(dsn)

c = conn.cursor()
c.execute("SELECT 1")

9
经过测试,使用psycopg2 2.5.2和psql 8.4得出的结果是,无论如何隔离级别始终为零。 - Zaar Hai

5

如何检查连接是否关闭:

  • 如果连接已关闭,则conn.closed为1,否则为0。

  • 如果已关闭,不仅在查询时会引发psycopg2.InterfaceError异常,而且在上下文管理器with conn:中也会引发异常。

  • 然后需要重新建立连接。例如,读取密码并放入.connect(..)中。


1

解决连接维护问题的最终方案是最好使用连接池来实施,它负责维护活动连接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接