使用带有psycopg2的try/except或"with closing"?

sky*_*ler 14 python postgresql psycopg2

我在Python中使用Psycopg2来访问PostgreSQL数据库.我很好奇是否可以安全地使用with closing()模式来创建和使用游标,或者我应该使用显式try/except包装查询.我的问题是关于插入或更新,以及交易.

据我所知,所有Psycopg2查询都发生在一个事务中,并且由调用代码来提交或回滚事务.如果在with closing(...块内发生错误,是否发出回滚?在旧版本Psycopg2的,回滚被明确发出close(),但不是这种情况了(见http://initd.org/psycopg/docs/connection.html#connection.close).

通过一个例子,我的问题可能更有意义.这是一个使用的例子with closing(...

with closing(db.cursor()) as cursor:
     cursor.execute("""UPDATE users                    
             SET password = %s, salt = %s
             WHERE user_id = %s""",
             (pw_tuple[0], pw_tuple[1], user_id))
     module.rase_unexpected_error()
     cursor.commit()
Run Code Online (Sandbox Code Playgroud)

当module.raise_unexpected_error()引发错误时会发生什么?交易是否回滚?据我了解事务,我要么提交它们要么回滚它们.那么在这种情况下,会发生什么?

或者我可以这样写我的查询:

cursor = None
try:
    cursor = db.cursor()
    cursor.execute("""UPDATE users                    
            SET password = %s, salt = %s
            WHERE user_id = %s""",
            (pw_tuple[0], pw_tuple[1], user_id))
    module.rase_unexpected_error()
    cursor.commit()
except BaseException:
    if cursor is not None:
        cursor.rollback()
finally:
    if cursor is not None:
        cursor.close()
Run Code Online (Sandbox Code Playgroud)

另外我应该提一下,我不知道Psycopg2的连接类cursor()方法是否会引发错误(文档没有说)所以更安全而不是抱歉,不是吗?

我应该使用哪种方法发布查询和管理事务?

voi*_*hos 7

你对Psycopg2文档的链接解释了它本身,不是吗?

...请注意,在未提交更改的情况下关闭连接将 导致任何挂起的更改被丢弃,就像执行了ROLLBACK一样(除非选择了不同的隔离级别:请参阅set_isolation_level()).

版本2.2中已更改:之前在close()上由Psycopg发出了显式的ROLLBACK.该命令可能已在不适当的时间发送到后端,因此Psycopg当前依赖后端隐式丢弃未提交的更改.虽然在事务期间关闭连接时(状态为STATUS_IN_TRANSACTION),某些中间件会出现行为不正确的情况,例如PgBouncer报告不干净的服务器并丢弃连接.要避免此问题,您可以确保在关闭之前使用commit()/ rollback()终止事务.

因此,除非您使用不同的隔离级别或使用PgBouncer,否则您的第一个示例应该可以正常工作.但是,如果您希望对事务期间发生的事情进行更精细的控制,那么try/except方法可能是最好的,因为它与数据库事务状态本身并行.