2016-07-14 148 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')))''。 –

相關問題