我有一个Flask,mysql,它使用一个SQLAlchemy服务器。我想扩展数据库设置,使之具有一个只读的从服务器,这样我就可以在继续写入主数据库服务器的同时,在主服务器和从服务器之间分配读操作。
我已经看过几个选项,我相信我不能用普通的SQLAlchemy做到这一点。取而代之的是,我计划在我的webapp中创建2个数据库句柄,分别用于主数据库服务器和从数据库服务器。然后使用一个简单的随机值,使用主/从db句柄进行"SELECT“操作。
然而,我不确定这是否是使用SQLAlchemy的正确方式。关于如何做到这一点有什么建议/小贴士吗?
发布于 2012-01-24 09:36:22
我在http://techspot.zzzeek.org/2012/01/11/django-style-database-routers-in-sqlalchemy/的博客上有一个如何做到这一点的例子。基本上,您可以增强会话,使其在逐个查询的基础上从主或从中进行选择。这种方法的一个潜在问题是,如果您有一个调用六个查询的事务,您可能最终会在一个request....but中同时使用两个从机,我们只是试图模仿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)来调用注册表来获取当前线程的实际会话对象,如果它不存在就创建它-然而,由于我们传递了一个参数,scoped_session将断言我们在这里创建的会话绝对是全新的。
对于所有后续的SQL,您将其指向“从”。然后,当请求结束时,您将确保Flask应用程序正在调用Session.remove()来清除该线程的注册表。当注册表下一次在同一线程上使用时,它将是一个绑定回"master“的新会话。
或者是一个变种,你只想对那个调用使用"slave“,这是”安全的“,因为它会将任何现有的绑定恢复回会话:
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有某种“请求开始”事件,你可以在那个时候设置它。
发布于 2016-05-12 11:49:22
或者,我们可以尝试另一种方法。例如,我们可以声明两个不同的类,所有的实例属性都是相同的,但是__bind__类属性是不同的。因此,我们可以使用rw类进行读写,使用r类进行只读。:)
我认为这种方式更容易、更可靠。:)
我们声明两个db模型,因为我们可以在两个不同的db中拥有具有相同名称的表。这样,当两个模型具有相同的__tablename__.时,我们也可以绕过'extend_existing‘错误
下面是一个示例:
app = Flask(__name__)
app.config['SQLALCHEMY_BINDS'] = {'rw': 'rw', 'r': 'r'}
db = SQLAlchemy(app)
db.Model_RW = db.make_declarative_base()
class A(db.Model):
__tablename__ = 'common'
__bind_key__ = 'r'
class A(db.Model_RW):
__tablename__ = 'common'
__bind_key__ = 'rw' https://stackoverflow.com/questions/8947918
复制相似问题