3

Pythonを使用してMySQLに接続するためにMySQLdbを使用しています。私のテーブルはすべて InnoDB で、トランザクションを使用しています。

関数間でトランザクションを「共有」する方法を考え出すのに苦労しています。次の疑似コードを検討してください。

def foo():
    db = connect()
    cur = db.cursor()
    try:
        cur.execute(...)
        conn.commit()
    except:
        conn.rollback()

def bar():
    db = connect()
    cur = db.cursor()
    try:
        cur.execute(...)
        foo()  # note this call
        conn.commit()
    except:
        conn.rollback()

コードのいくつかのポイントで を呼び出す必要がfoo()あり、いくつかのポイントで を呼び出す必要がありますbar()。ここでのベストプラクティスは何ですか? 外部で呼び出されたが内部では呼び出されなかった場合、foo()への呼び出しをどのように伝えますか? およびを呼び出す複数のスレッドがあり、 への呼び出しが同じ接続オブジェクトを返さない場合、これは明らかにより複雑になります。commit()bar()bar()foo()bar()connect()

アップデート

自分に合った解決策を見つけました。connect()呼び出されたときに値をインクリメントするようにラップしました。呼び出すcommit()と、その値が減少します。が呼び出され、そのカウンターが > 0 の場合commit()、コミットは行われず、値が減分されます。したがって、次のようになります。

def foo():
    db = connect()  # internal counter = 1
    ...
    db.commit()  # internal counter = 0, so commit


def bar():
    db = connect()  # internal counter = 1
    ...
    foo()  # internal counter goes to 2, then to 1 when commit() is called, so no commit happens
    db.commit() # internal counter = 0, so commit
4

3 に答える 3

0

IMO が接続オブジェクトを渡しfoobar

于 2013-02-19T21:37:13.347 に答える
0

この場合、Python のデフォルトの関数引数を利用できます。

def foo(cur=None):
    inside_larger_transaction = False
    if cursor is None:
        db = connect()
        cur = db.cursor()
        inside_larger_transaction = True
    try:
        cur.execute(...)
        if not inside_larger_transaction:
             conn.commit()
    except:

        conn.rollback()

したがって、barが を呼び出しfooている場合は、カーソル オブジェクトをパラメーターとして渡すだけです。

小さな関数ごとに異なるカーソルオブジェクトを作成することにあまり意味がないとは限りません-オブジェクトのメソッドとしていくつかの関数を記述し、カーソル属性を持たせるか、常に明示的にカーソルを渡す必要があります(この場合、別の名前付きパラメーターを使用して、現在の関数が主要なトランザクションの一部であるかどうかを示します)

もう 1 つのオプションは、コンテキスト マネージャー__exit__クラスを作成してコミットを行い、その中にすべてのトランザクションをカプセル化することです。したがって、どの関数もトランザクション コミットを行うべきではありません。このメソッドでtransaction.commit と transaction.rollback 呼び出しの両方を保持します。物体。

class Transaction(object):
    def __enter__(self):
       self.db = connect()
       cursor = self.db.cursor()
       return cursor
   def __exit__(self, exc_type, exc_value, traceback):
       if exc_type is None:
           self.db.commit()
       else:
           self.db.rollback()

そして、次のように使用してください:

def foo(cursor):
    ...

def foo(cur):
        cur.execute(...)


def bar(cur):
    cur.execute(...)
    foo(cur)

with Transaction() as cursor:
    foo(cursor)


with Transaction() as cursor:
    bar(cursor)
于 2013-02-20T02:18:33.250 に答える
0

関数の外部で接続を宣言し、それらを引数として関数に渡します

foo(cur, conn)
bar(cur, conn)
于 2013-02-19T21:38:10.823 に答える