我的博客http://techspot.zzzeek.org/2012/01/11/django-style-database-routers-in-sqlalchemy/上有一个如何执行此操作的示例。基本上,您可以增强 Session 以便它在逐个查询的基础上从主服务器或从服务器中进行选择。这种方法的一个潜在故障是,如果您有一个调用六个查询的事务,您最终可能会在一个请求中同时使用两个从属设备……但我们只是在尝试模仿 Django 的功能:)
一种稍微不那么神奇的方法,也更明确地确定了我使用的使用范围,是视图可调用对象(无论它们在 Flask 中调用什么)的装饰器,如下所示:
@with_slave
def my_view(...):
# ...
with_slave 会做这样的事情,假设你有一个 Session 和一些引擎设置:
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 将断言我们在这里创建的 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
对于这些装饰器中的每一个,您都可以反转事物,将 Session 绑定到一个“从属”,装饰器将其置于“主”以进行写操作。如果在这种情况下你想要一个随机的奴隶,如果 Flask 有某种“请求开始”事件,你可以在那个时候设置它。