Psycopg2:退出包含 try/except 的 'with' 语句时连接未提交

Psycopg2: connection not committing when exiting 'with' statement containing a try/except

首先,我想声明我很清楚 psycopg 打开一个事务,需要提交才能进行数据库更新。

但是这里引用了关于提交的文档:

commit()

Commit any pending transaction to the database.

By default, Psycopg opens a transaction before executing the first command: if commit() is not called, the effect of any data manipulation will be lost.

The connection can be also set in “autocommit” mode: no transaction is automatically open, commands have immediate effect. See Transactions control for details.

Changed in version 2.5: if the connection is used in a with statement, the method is automatically called if no exception is raised in the with block.

回滚也类似:

rollback()

Roll back to the start of any pending transaction. Closing a connection without committing the changes first will cause an implicit rollback to be performed.

Changed in version 2.5: if the connection is used in a with statement, the method is automatically called if an exception is raised in the with block.

然而这似乎对我不起作用。也许我很挑剔,并且应该始终养成显式提交的习惯(但是如果我忘记它会发生回滚,那就太好了)。我想知道是否有人遇到了同样的问题,或者我是否错误地使用了我的 with 语句。

我的代码如下所示:

import psycopg2
from contextlib import closing

with closing(psycopg2.connect(
                               #conn params
                              ) as conn, \
     closing(conn.cursor()) as cur:

     try:
         sql = #query
         cur.execute(sql)

         output = cur.statusmessage
         print output

     except Exception, e :
         print "Error message : {}".format(e)
         raise

这行不通。查询本身没有问题,因为我得到: 更新 842518 正如预期的那样输出。但是,由于我的数据库未更新,因此显然未提交来自连接的更改。 如果我添加

conn.commit()

在 try 语句中它有效,但重点是避免这样做。

我的 psycopg2 版本是 2.6。

Link to doc

在关闭时包装连接和游标对象很可能会扰乱它们的上下文处理; they are context managers them selvesclosing 包装器只会在退出时调用它们的 close() 方法。

在 with 块中使用游标时无需手动调用 close()。这同样不适用于连接;只有事务在退出 with 块时结束。这是设计使然,因此您可以在多个 with 块中使用相同的连接:

Note that, unlike file objects or other resources, exiting the connection’s with block doesn’t close the connection but only the transaction associated with it: a connection can be used in more than a with statement and each with block is effectively wrapped in a separate transaction

例如,您可以将 closing 中的连接包装在最外层的 with-block 中,然后在内部 with-block 中使用相同的连接进行事务处理等:

# This'll handle closing the connection
with closing(psycopg2.connect(...)) as conn:
    # This'll handle the transaction and closing the cursor
    with conn, conn.cursor() as cur:
        ...