【问题标题】:Flask-SQLAlchemy - on the fly connections to multiple databasesFlask-SQLAlchemy - 与多个数据库的动态连接
【发布时间】:2016-08-21 01:09:29
【问题描述】:

我有一个flask webapp,用户可以在其中连接到自己的 mysql 数据库并查询自己的表

使用 flask-sqlalchemy 创建多个连接(到不同数据库)的最佳方法是什么。似乎需要使用scoped_sessionsessionmaker 来完成,但我似乎无法理解它。

也是问题的第二部分,一旦我为其中一个用户创建了到 mysql 数据库的连接,我如何跨请求保持连接?

目前,我将每个用户的连接字符串放在烧瓶会话变量中,并在每个新请求时创建引擎和连接

engine = create_engine(connection_string, convert_unicode=True)
conn = engine.connect()
db_session = Session(bind=conn) # Session - i create it globally on the __init__ like this Session = scoped_session(sessionmaker()) and import it in the view

## Query using the db_session

为每个请求创建引擎和连接似乎非常浪费 - 连接不能跨请求保持吗?

【问题讨论】:

  • 我在执行相同任务时遇到了麻烦。您能否发布您的答案,请解释在应用程序启动后您是如何连接新数据库的?

标签: mysql session flask sqlalchemy flask-sqlalchemy


【解决方案1】:

一个数据库

引擎允许您使用连接池。默认情况下,它将跨请求保持连接。基本用法(没有像scoped_sessionsessionmaker 这样的花哨的东西)是这样的:

engine = create_engine(...)

@app.route(...)
def foo():
    session = Session(bind=engine)
    try:
        session.query(...)
        session.commit()
    finally:
        session.close()
    return ""

除此之外,您还可以添加scoped_sessionsessionmaker

engine = create_engine(...)
Session = sessionmaker(bind=engine)
session = scoped_session(Session, scopefunc=...)

@app.route(...)
def foo():
    try:
        session.query(...)
        session.commit()
    finally:
        session.close()
    return ""

flask-sqlalchemy 提供所有这些,让您的生活更轻松:

db = SQLAlchemy(app)

@app.route(...)
def foo():
    db.session.query(...)
    db.session.commit()
    return ""

多个数据库

您可以轻松地将这个概念扩展到多个数据库:

engine1 = create_engine(...)
engine2 = create_engine(...)

@app.route(...)
def foo():
    session = Session(bind=choose_engine_for_user())
    try:
        session.query(...)
        session.commit()
    finally:
        session.close()
    return ""

当您添加scoped_sessionsessionmaker 时:

engine1 = create_engine(...)
engine2 = create_engine(...)
Session1 = sessionmaker(bind=engine1)
Session2 = sessionmaker(bind=engine2)
session1 = scoped_session(Session1, scopefunc=...)
session2 = scoped_session(Session2, scopefunc=...)

@app.route(...)
def foo():
    session = choose_session_for_user()
    try:
        session.query(...)
        session.commit()
    finally:
        session.close()
    return ""

当您有许多数据库时,这会有点烦人,在这种情况下,您可能应该编写一个注册表类来跟踪所有引擎和会话:

class SessionRegistry(object):
    _registry = {}

    def get(self, url, **kwargs):
        if url not in self._registry:
            engine = create_engine(url, **kwargs)
            Session = session_maker(bind=engine)
            session = scoped_session(Session, scopefunc=...)
            self._registry[url] = session
        return self._registry[url]

registry = SessionRegistry()

@app.route(...)
def foo():
    session = registry.get(...)
    try:
        session.query(...)
        session.commit()
    finally:
        session.close()
    return ""

您需要在其上添加某种 LRU,这样就不会无限制地创建引擎。

flask-sqlalchemy 支持有限形式的多个数据库,其中每个模型都连接到不同的数据库。如果这适用于您,文档是 here

【讨论】:

  • 感谢 Univerio。问题是我没有用于应用程序本身的多个数据库 - 它是应用程序用户需要即时创建与其数据库的连接以查询其表的应用程序用户。您能否详细说明“用于跟踪所有引擎和会话的注册表类”
  • @sarul 见编辑。如果您需要能够在应用程序的生命周期内连接到任意(无限数量)数据库,那么您需要在注册表顶部添加某种 LRU 以控制内存泄漏。
  • 完美。感谢 Univerio 的详细回复。
  • 如何在flask-sqlalchemy中使用这种方式。绑定对我来说不是正确的方法。我也需要即时更改数据库。 app.config[ 'SQLALCHEMY_DATABASE_URI'] = DataBaseConfig.generate_database_uri() 用于整个应用程序。如何在 flask-sqlalchemy 中使用您的解决方案?
  • @AmirShabani 使用什么? SessionRegistry?你可以只复制代码,然后添加一些 LRU 逻辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-22
  • 2021-11-02
相关资源
最近更新 更多