23

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()

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()

また、Psycopg2 の接続クラスcursor()メソッドがエラーを発生させる可能性があるかどうかはわかりません (ドキュメントには記載されていません)。

クエリを発行してトランザクションを管理するには、どの方法を使用すればよいですか?

4

1 に答える 1

9

Psycopg2 docsへのリンクは、それ自体を説明していますね?

... 最初に変更をコミットせずに接続を閉じると 、ROLLBACK が実行されたかのように保留中の変更が破棄されることに注意してください(別の分離レベルが選択されていない限り: set_isolation_level() を参照してください)。

バージョン 2.2 で変更: 以前は、明示的な ROLLBACK が close() で Psycopg によって発行されていました。コマンドが不適切なタイミングでバックエンドに送信された可能性があるため、Psycopg は現在、コミットされていない変更を暗黙的に破棄するためにバックエンドに依存しています。一部のミドルウェアは、トランザクション中に接続が閉じられた場合 (ステータスが STATUS_IN_TRANSACTION の場合) に正しく動作しないことが知られています。たとえば、PgBouncer が汚れたサーバーを報告し、接続を破棄します。この問題を回避するには、閉じる前に commit()/rollback() でトランザクションを確実に終了することができます。

したがって、別の分離レベルを使用していないか、PgBouncer を使用していない限り、最初の例は問題なく動作するはずです。ただし、トランザクション中に何が起こるかをより細かく制御したい場合は、データベース トランザクションの状態自体に対応するため、try/except メソッドが最適です。

于 2012-09-26T19:04:04.230 に答える