http://techspot.zzzeek.org/2012/01/11/django-style-database-routers-in-sqlalchemy/ 。基本的に、セッションを拡張して、クエリごとにマスターまたはスレーブから選択することができます。このアプローチの潜在的な不具合の1つは、6つのクエリを呼び出すトランザクションが1つある場合、1つのリクエストで両方のスレーブを使用することになる可能性があることです。しかし、Djangoの機能を模倣しようとしているだけです:)
私が使用した使用範囲をより明確に確立する、少し魔法の少ないアプローチは、次のように、ビューの呼び出し可能オブジェクト(Flaskで呼び出されるものは何でも)のデコレータです。
@with_slave
def my_view(...):
# ...
セッションがあり、いくつかのエンジンが設定されていると仮定すると、with_slaveは次のようになります。
master = create_engine("some DB")
slave = create_engine("some other DB")
Session = scoped_session(sessionmaker(bind=master))
def with_slave(fn):
def go(*arg, **kw):
s = Session(bind=slave)
return fn(*arg, **kw)
return go
アイデアは、Session(bind=slave)
を呼び出すことです レジストリを呼び出して、現在のスレッドの実際のSessionオブジェクトを取得し、存在しない場合は作成します。ただし、引数を渡すため、scoped_sessionは、ここで作成しているセッションが完全に新しいことを表明します。
後続のすべてのSQLの「スレーブ」をポイントします。次に、リクエストが終了したら、FlaskアプリがSession.remove()
を呼び出していることを確認します。 そのスレッドのレジストリをクリアします。次にレジストリが同じスレッドで使用されると、「マスター」にバインドされた新しいセッションになります。
または、その呼び出しにのみ「スレーブ」を使用するバリアント。これは、既存のバインドをセッションに復元するという点で「より安全」です。
def with_slave(fn):
def go(*arg, **kw):
s = Session()
oldbind = s.bind
s.bind = slave
try:
return fn(*arg, **kw)
finally:
s.bind = oldbind
return go
これらのデコレータのそれぞれについて、逆にすることができます。セッションを「スレーブ」にバインドし、デコレータが書き込み操作のために「マスター」に配置します。その場合にランダムなスレーブが必要な場合、Flaskに何らかの「リクエスト開始」イベントがあれば、その時点で設定できます。