2016-07-14 152 views
4

我正在Flask项目上工作,我正在使用Flask-SQLAlchemy。
我需要使用多个已有的数据库。
我创建的“应用程序”对象和SQLAlchemy的一个:
Flask-SQLAlchemy - 会话如何与多个数据库一起工作?

from flask import Flask 
from flask_sqlalchemy import SQLAlchemy 


app = Flask(__name__) 
db = SQLAlchemy(app) 

在我设置默认连接和附加结合的结构:

SQLALCHEMY_DATABASE_URI = 'postgresql://pg_user:[email protected]_server/pg_db' 
SQLALCHEMY_BINDS = { 
    'oracle_bind': 'oracle://oracle_user:[email protected]_server/oracle_schema', 
    'mssql_bind': 'mssql+pyodbc://msssql_user:[email protected]_server/mssql_schema?driver=FreeTDS' 
} 

然后,我使用创建的表的模型声明系统,并根据需要设置 __bind_key__参数以指示表位于哪个数据库中。
例如:

class MyTable(db.Model): 
    __bind_key__ = 'mssql_bind' 
    __tablename__ = 'my_table' 

    id = db.Column(db.Integer, nullable=False, primary_key=True) 
    val = db.Column(db.String(50), nullable=False) 

这样一切正常,当我这样做是正确的数据库上进行查询。

阅读SQLAlchemy的文档和烧瓶SQLAlchemy的文档,我明白这事 (我写下来,检查我理解正确):

  • 您可以通过会话处理事务。
  • 在SQLAlchemy中,您可以将会话与特定引擎绑定。
  • 瓶-SQLAlchemy中自动创建在请求启动会话(scoped_session),并破坏它在请求端

所以我可以做:

record = MyTable(1, 'some text') 
db.session.add(record) 
db.session.commit() 

我不明白什么当我们在Flask-SqlAlchemy中使用关于会话的多个数据库时发生。

我核实,该系统能够在正确的表在正确数据库通过__bind_key__参数绑定, 我可以,因此,通过db.session插在不同的数据库中的数据,并在提交时,一切都将被保存。

但是,我不能理解Flask-SQLAlchemy是否创建多个会话(每个引擎一个会话)或者以不同的方式管理事物。
在这两种情况下,如何引用特定数据库的会话/事务?
如果我使用db.session.commit()系统会在所有涉及的数据库上进行提交,但如果我只想提交一个数据库,该怎么办?
我会做这样的事情:

db.session('mssql_bind').commit() 

,但我无法弄清楚如何做到这一点。

我还看到一个烧瓶SQLAlchemy的实施应该缓解这些情况的管理:

问题:https://github.com/mitsuhiko/flask-sqlalchemy/issues/107
实现:https://github.com/mitsuhiko/flask-sqlalchemy/pull/249

但我无法弄清楚如何使用它。

在Flask-SQLAlchemy中,我怎样才能专门为每个单引擎管理会话?

+0

相关:[在Flask中使用具有不同绑定的表的相同名称](// stackoverflow.com/q/15336778) –

回答

12

Flask-SQLAlchemy使用customized session,它根据给定的__bind_key__ attribute in mapped class处理绑定路由。在引擎盖下,它实际上将该键添加到创建的表的信息中。换句话说,Flask不会创建多个会话,每个绑定会创建一个会话,但会根据绑定键为路由以更正可连接(引擎/连接)的单个会话。请注意,vanilla SQLAlchemy开箱即用similar functionality

在这两种情况下,如何引用特定数据库的会话/事务? 如果我使用db.session.commit(),系统会在所有涉及的数据库上执行提交操作,但如果我只想提交单个数据库,该怎么办?

使用会话拥有的连接来颠覆并向特定数据库中的会话发出提交可能不是一个好主意。会话是一个整体,对于对象实例来说是keeps track of state,当需要时刷新对数据库的更改等。这意味着会话处理的事务不仅仅是数据库事务,还是会话自己的事务。所有应该提交和回滚为一体。

你可以从另一方面创造新的SQLAlchemy(或烧瓶的SQLAlchemy)会话的可能join the ongoing transaction in one of the binds

session = db.create_scoped_session(
    options=dict(bind=db.get_engine(app, 'oracle_bind'), 
       binds={})) 

这是拉入请求是关于什么的。它允许使用现有的事务连接绑定一个新的Flask-SQLAlchemy会话。例如在测试中,这非常有用,这可以从拉取请求的基本原理中看出。这样你就可以拥有一个“主”事务,例如可以回滚测试中完成的所有事情。

请注意,如果存在bind_keySignallingSession将始终参考db.get_engine()方法。这意味着示例会话无法在没有绑定键的情况下查询表,但您的oracle数据库中不存在该表,但仍可用于使用密钥的表。

您链接到另一方面的问题确实列表的方式来发出SQL特定的绑定:

rows = db.session.execute(query, params, 
          bind=db.get_engine(app, 'oracle_bind')) 

有上市以及其他不太明确的方法,但明确的是优于隐。

+0

感谢您的详细解答。 – corros

+0

还有一个问题:我如何使用Flask-SQLAlchemy在两个不同的数据库上处理两个独立的事务? 是否可以或应该使用“纯”SQLAlchemy? – corros

+0

您可以使用上述方法创建2个新会话。它们将是Flask-SQLAlchemy的'SignallingSession'会话,如果绑定键不是'None',它们总是在'get_bind()'中查询'db'全局。新会话将不会在两个不同的数据库上处理独立事务,而会在所有数据库上处理两个不同的事务会话。如果你真的希望成为数据库特定的,则恢复使用vanilla SQLAlchemy会话:'oracle_session = scoped_session(sessionmaker(bind = db.get_engine(app,'oracle_bind')))''。 –

相关问题