Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 读从、读写主设置_Python_Mysql_Sqlalchemy_Flask_Flask Sqlalchemy - Fatal编程技术网

Python 读从、读写主设置

Python 读从、读写主设置,python,mysql,sqlalchemy,flask,flask-sqlalchemy,Python,Mysql,Sqlalchemy,Flask,Flask Sqlalchemy,我有一个烧瓶,SQLAlchemy webapp,它使用一个mysql服务器。我想扩展数据库设置,使之具有只读从属服务器,这样我可以在继续向主数据库服务器写入数据的同时,在主服务器和从属服务器之间分散读取 我已经看了几个选项,我相信我不能用普通的SQLAlchemy做到这一点。相反,我计划在我的webapp中创建两个数据库句柄,一个用于主数据库服务器,一个用于从数据库服务器。然后使用一个简单的随机值,使用主/从db句柄进行“选择”操作 然而,我不确定这是否是使用SQLAlchemy的正确方法。关

我有一个烧瓶,SQLAlchemy webapp,它使用一个mysql服务器。我想扩展数据库设置,使之具有只读从属服务器,这样我可以在继续向主数据库服务器写入数据的同时,在主服务器和从属服务器之间分散读取

我已经看了几个选项,我相信我不能用普通的SQLAlchemy做到这一点。相反,我计划在我的webapp中创建两个数据库句柄,一个用于主数据库服务器,一个用于从数据库服务器。然后使用一个简单的随机值,使用主/从db句柄进行“选择”操作


然而,我不确定这是否是使用SQLAlchemy的正确方法。关于如何实现这一点,有什么建议/提示吗?提前谢谢。

我在我的博客上有一个如何做到这一点的例子。基本上,您可以增强会话,使其在逐个查询的基础上从主会话或从会话中进行选择。这种方法的一个潜在缺陷是,如果您有一个事务调用六个查询,那么您可能会在一个请求中同时使用两个从机……但我们只是在尝试模仿Django的特性:)

我使用过一种稍微不那么神奇的方法,它更明确地确定了使用范围,即视图可调用项(无论在Flask中如何调用)上的装饰器,如下所示:

@with_slave
def my_view(...):
   # ...
如果您有一个会话和一些引擎设置,那么使用_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()
,以清除该线程的注册表。当注册表下次在同一线程上使用时,它将是绑定回“主”的新会话

或者是一种变体,您希望仅为该调用使用“从属”,这更“安全”,因为它将任何现有绑定恢复回会话:

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有某种“请求开始”事件,您可以在该点设置它。

或者,我们可以尝试另一种方法。例如,我们可以声明两个不同的类,所有实例属性都相同,但
\uuu绑定\uu
类属性不同。因此,我们可以使用rw类执行读/写操作,r类执行只读操作:

我认为这种方法更简单、更可靠。:)

我们声明两个db模型,因为我们可以在两个不同的db中使用相同名称的表。这样,当两个模型具有相同的\uuuuu tablename\uuuu时,我们也可以绕过“extend\u 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'    

这很有帮助。感谢所有关于sqlalchemy.Rad评论的出色工作,还有很棒的代码示例!如果sqlalchemy能够自动进行查询分析和路由,那就太好了,但在一个查询可能会导致tmp表或其他写入操作的世界中,可能会导致通常为只读的操作,这需要在提交查询之前从后端请求查询计划,这比大多数情况下更麻烦。我们有“查询分析”选项,虽然它要求你自己写分析。水平切分系统演示了这种技术的一个示例,请参见.Hooks,它具有一个回调函数,用于决定如何切分查询,但实际上,像用于分离读操作和写操作的适当查询检查分类这样的东西可能超出了大多数sqlalchemy用户的范围。实际上,我希望在不久的将来,这些策略的一些基本实现可以作为SA中的样板提供。在某些情况下,分析查询以选择会话是个坏主意。您希望读操作与写操作在同一事务中完成,以防读操作受到写操作的影响。假设在同一个调用中,删除表中的一行,然后返回该表所有记录的一列总和。如果使用两个不同的事务,则总和将包含您刚刚删除的行,因为另一个事务尚未提交。您能否通过提供一个创建、定义和使用具有不同读写访问能力的两个数据库的示例来改进您的答案