4

Tornadoで構築された小さな Web アプリがあり、データ ストレージにZODBを使用したいと考えています。ZODB ドキュメントによると、マルチスレッド プログラムはサポートされていますが、スレッドごとに新しい接続を開始する必要があります。それは私が何かをしなければならないことを意味すると思います

### On startup
dbFilename = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Data.fs")
db = DB(FileStorage(dbFilename))

### Example handler
class Example(tornado.web.RequestHandler):
    def get(self):
        try:
            conn = db.open()
            root = conn.root()
            ### do stuff with root here
            root._p_changed = 1  ## Include these lines for writes
            transaction.commit() ## on sub-elements
        finally:
            conn.close()

まず、新しい接続は、すべての db 対話ハンドラーまたは書き込みを行うハンドラーにまだ必要ですか? 起動時に 1 つの接続を開始し、それをすべての読み取りに使用してから、何かを書き込む必要がある場合にのみ上記の接続の歌と踊りを行うのは合理的でしょうか?

第二に、Python でそのパターンを抽象化する慣用的な方法は何ですか? 私は次のようなものを持っています

def withDB(fn):
    try:
        conn = db.open()
        root = conn.root()
        res = fn(root)
        root._p_changed = 1
        transaction.commit()
        return res
    finally:
        conn.close()

def delete(formName):
    def local(root):
        ### do stuff with root here
    return withDB(local)

心に留めていますが、それはおそらく私の Lisp の表示です。

アプローチに関する一般的なヘッドチェックも歓迎します。

4

1 に答える 1

4

スレッドごとに新しい接続を作成する必要があります。ZODB は各接続に一貫したトランザクションごとのビュー (MVCC、マルチビュー同時実行制御) を提供するため、読み取りの場合でも別の接続が必要です。接続は、1 つのスレッドで順次要求に再利用できます。

したがって、接続には、 によって提供されるスレッドごとのプールを使用しZODB.DB、おそらくリクエストごとに接続をキャッシュします ( pyramid_zodbconnのように)。

リクエスト ハンドラ内で、トランザクション マネージャをコンテキスト マネージャとして使用できます。

class Example(tornado.web.RequestHandler):
    def get(self):
        connection = some_connection_pool.get_connection()
        with transaction.manager:
            root = conn.root()
            res = fn(root)
            root._p_changed = 1

オブジェクトをコンテキスト マネージャとして使用transaction.managerすると、トランザクションが開始時に開始され、例外なく終了時にコミットされ、終了時に例外が発生して中止されることが保証されます。

ZODB 接続を処理するコンテキスト マネージャーを作成することもできます。

from contextlib import contextmanager

@contextmanager
def zodbconn(db):
    conn = db.open()
    yield conn.root()
    conn.close()

次に、それをトランザクション マネージャーと共にコンテキスト マネージャーとして使用します。

class Example(tornado.web.RequestHandler):
    def get(self):
        with zodbconn(db) as root, transaction.manager:
            res = fn(root)
            root._p_changed = 1

このコンテキスト マネージャはデータベース オブジェクトを受け取り、ルート オブジェクトを返し、コンテキストが再び終了すると自動的に接続を閉じます。

于 2013-04-09T19:56:56.750 に答える