【问题标题】:How can SQLAlchemy be taught to recover from a disconnect?如何教 SQLAlchemy 从断开连接中恢复?
【发布时间】:2015-03-29 00:44:05
【问题描述】:

根据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.

由于终端上打印了“pinging server”,因此似乎可以安全地得出结论,事件侦听器已附加。如何教 SQLAlchemy 从断开连接中恢复?

【问题讨论】:

    标签: python sqlalchemy psycopg2


    【解决方案1】:

    看起来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 方法,并在那时采取一些措施来替换您的连接。

    【讨论】:

    • 您似乎已经确认 SQLAlchemy 文档具有误导性。如果每个查询都需要包装在辅助方法中,则 Pool 在这种无值的上下文中会执行异常处理和显式恢复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-17
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    相关资源
    最近更新 更多