131

簡単な質問: SQLAlchemyでは、DB と対話する必要があるたびに、一度呼び出して、結果のクラスを呼び出すことについて説明しています。私にとってそれは、私が最初に行うか、または同様のことを行う2番目のことを意味します。sessionmaker()Session()session.add(x)

from project import Session
session = Session()

これまで私が行っていたことはsession = Session()、モデルで一度呼び出しを行い、アプリケーションのどこにでも同じセッションを常にインポートすることでした。これは Web アプリケーションであるため、通常は同じことを意味します (1 つのビューが実行される場合)。

しかし、違いはどこにありますか?1 つのセッションを常に使用することと、機能が完了するまでデータベースに使用することと、次に DB と通信するときに新しいセッションを作成することの不利な点は何ですか?

複数のスレッドを使用する場合、それぞれが独自のセッションを取得する必要があります。しかし、を使用してscoped_session()、問題が存在しないことをすでに確認していますよね?

私の仮定が間違っているかどうかを明確にしてください。

4

2 に答える 2

295

sessionmaker()Sessionはファクトリであり、新しいオブジェクトを作成するための構成オプションを 1 か所だけに配置することを奨励するためにあります。これはオプションでSession(bind=engine, expire_on_commit=False)あり、 new が必要なときはいつでも簡単に呼び出すことができますがSession、冗長で冗長であることを除けば、それぞれがこの冗長性の問題に新しい .そしてもっと紛らわしい方法。

必要なときにオブジェクトを作成するのに役立つsessionmaker()ツールにすぎません。Session

次の部分。Session()問題は、さまざまな時点で新しいものを作成することと、最初から最後まで使用することの違いは何だと思います。答えは、あまりありません。 Session入れたすべてのオブジェクトのコンテナであり、開いているトランザクションも追跡します。rollback()またはを呼び出した時点commit()で、トランザクションは終了し、SessionSQL を再び発行するように呼び出されるまで、 はデータベースに接続されません。オブジェクトに保留中の変更がない場合、マップされたオブジェクトへのリンクは弱い参照です。そのためSession、アプリケーションがマップされたオブジェクトへのすべての参照を失うと、それ自体が空になり、新しい状態に戻ります。デフォルトのままにしておくと"expire_on_commit"設定すると、コミット後にすべてのオブジェクトが期限切れになります。それSessionが 5 分から 20 分間持続し、次にデータベースを使用するときにあらゆる種類の変更があった場合、次にそれらのオブジェクトにアクセスすると、たとえそれらがメモリに残っていたとしても、まったく新しい状態がロードされます。 20分間。

SessionWeb アプリケーションでは、同じものを何度も使用するのではなく、リクエストごとにまったく新しいものを作成してみませんか。このプラクティスにより、新しいリクエストが「クリーン」に開始されることが保証されます。前のリクエストの一部のオブジェクトがまだガベージ コレクションされておらず、"expire_on_commit"おそらく off になっている場合、前のリクエストの状態がまだぶら下がっていて、その状態がかなり古い可能性さえあります。電源を入れたままにして、要求の最後expire_on_commitに確実に電話をかけるように注意している場合は問題ありませんが、新しい から始める場合は、きれいに始めていることに疑問の余地はありません。したがって、各リクエストを新しいcommit()rollback()SessionSessionこのフラグは、一連の操作の途中でexpire_on_commit呼び出す操作に対して多くの余分な SQL が発生する可能性があるため、最初からやり直すことを確認し、の使用をほとんどオプションにするための最も簡単な方法です。commit()これがあなたの質問に答えているかどうかはわかりません。

次のラウンドは、スレッド化について言及したものです。アプリがマルチスレッド化されているSession場合は、使用中の が何かに対してローカルであることを確認することをお勧めします。 scoped_session()デフォルトでは、現在のスレッドに対してローカルになります。Web アプリでは、リクエストに対してローカルの方が実際にはさらに優れています。Flask-SQLAlchemy は実際にカスタムの「スコープ関数」を送信してscoped_session()、リクエスト スコープのセッションを取得します。平均的な Pyramid アプリケーションは、セッションを「リクエスト」レジストリに貼り付けます。このようなスキームを使用する場合、「リクエストの開始時に新しいセッションを作成する」というアイデアは、物事をまっすぐに保つための最も簡単な方法のように見えます。

于 2012-08-31T23:45:40.017 に答える
36

zzzeek の優れた回答に加えて、使い捨ての自己完結型セッションをすばやく作成するための簡単なレシピを次に示します。

from contextlib import contextmanager

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker

@contextmanager
def db_session(db_url):
    """ Creates a context with an open SQLAlchemy session.
    """
    engine = create_engine(db_url, convert_unicode=True)
    connection = engine.connect()
    db_session = scoped_session(sessionmaker(autocommit=False, autoflush=True, bind=engine))
    yield db_session
    db_session.close()
    connection.close()

使用法:

from mymodels import Foo

with db_session("sqlite://") as db:
    foos = db.query(Foo).all()
于 2015-11-11T10:22:36.820 に答える