如何教导SQLAlchemy从断开连接中恢复?

时间:2015-01-29 17:16:33

标签: python sqlalchemy psycopg2

根据http://docs.sqlalchemy.org/en/rel_0_9/core/pooling.html#disconnect-handling-pessimistic,如果连接池中的条目不再有效,则可以检测SQLAlchemy重新连接。我创建了以下测试用例来测试它:

import subprocess
from sqlalchemy import create_engine, event
from sqlalchemy import exc
from sqlalchemy.pool import Pool

@event.listens_for(Pool, "checkout")
def ping_connection(dbapi_connection, connection_record, connection_proxy):
    cursor = dbapi_connection.cursor()
    try:
        print "pinging server"
        cursor.execute("SELECT 1")
    except:
        print "raising disconnect error"
        raise exc.DisconnectionError()
    cursor.close()

engine = create_engine('postgresql://postgres@localhost/test')

connection = engine.connect()

subprocess.check_call(['psql', str(engine.url), '-c',
    "select pg_terminate_backend(pid) from pg_stat_activity " +
    "where pid <> pg_backend_pid() " +
    "and datname='%s';" % engine.url.database],
    stdout=subprocess.PIPE)

result = connection.execute("select 'OK'")
for row in result:
    print "Success!", " ".join(row)

但是我没有恢复,而是收到了这个例外:

sqlalchemy.exc.OperationalError: (OperationalError) terminating connection due to administrator command
server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.

因为&#34; ping服务器&#34;打印在终端上似乎可以安全地得出结论事件监听器是附加的。如何教导SQLAlchemy从断开连接中恢复?

1 个答案:

答案 0 :(得分:5)

当你第一次从池中获得连接时,看起来checkout方法仅 被调用(例如你的connection = engine.connect()行)

如果您随后丢失了连接,则必须明确替换它,因此您可以抓取一个新连接,然后重试您的sql:

try:
    result = connection.execute("select 'OK'")
except sqlalchemy.exc.OperationalError:  # may need more exceptions here
    connection = engine.connect()  # grab a new connection
    result = connection.execute("select 'OK'")  # and retry

围绕每一个sql做一个很痛苦的事情,所以你可以使用类似的东西来包装数据库查询:

def db_execute(conn, query):
    try:
        result = conn.execute(query)
    except sqlalchemy.exc.OperationalError:  # may need more exceptions here (or trap all)
        conn = engine.connect()  # replace your connection
        result = conn.execute(query)  # and retry
    return result

以下内容:

result = db_execute(connection, "select 'OK'")

现在应该成功。

另一种选择是同时监听invalidate方法,并在此时采取一些措施来替换您的连接。