【问题标题】:How to SQLAlchemy database session create per Request如何为每个请求创建 SQLAlchemy 数据库会话
【发布时间】:2019-06-05 03:19:34
【问题描述】:

我有一个多租户 python falcon 应用程序。每个租户都有自己的数据库。在收到请求时,我需要连接到租户数据库。

但是这里有一种情况。数据库配置存储在另一个服务上,并且配置会定期更改。

我尝试在进程资源之前创建会话。但是在此更改后,sql 查询速度变慢。为了让这更快,我应该怎么做? 附言: 我用的是 PostgreSQL

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
import config
import json
import requests
class DatabaseMiddleware:
    def __init__(self):
        pass
    def process_resource(self, req, resp, resource, params):
        engineConfig = requests.get('http://database:10003/v1/databases?loadOnly=config&appId=06535108-111a-11e9-ab14-d663bd873d93').text
        engineConfig = json.loads(engineConfig)
        engine = create_engine(
            '{dms}://{user}:{password}@{host}:{port}/{dbName}'.format(
            dms= engineConfig[0]['config']['dms'],
            user= engineConfig[0]['config']['user'],
            password= engineConfig[0]['config']['password'],
            host= engineConfig[0]['config']['host'],
            port= engineConfig[0]['config']['port'],
            dbName= engineConfig[0]['config']['dbName']
        ))
        session_factory = sessionmaker(bind=engine,autoflush=True)
        databaseSession = scoped_session(session_factory)
        resource.databaseSession = databaseSession
    def process_response(self, req, resp, resource, req_succeeded):
        if hasattr(resource, 'mainDatabase'):
            if not req_succeeded:
                resource.databaseSession.rollback()
            self.databaseSession.remove()

【问题讨论】:

    标签: python python-3.x sqlalchemy multi-tenant falconframework


    【解决方案1】:

    您的方法可能是错误的,因为它违反了engine disposal 中描述的引擎实例的预期使用模式。引擎实例的生命周期应与中间件实例的生命周期相同。

    Engine 指的是一个连接池,这意味着在正常情况下,当 Engine 对象仍然驻留在内存中时,存在打开的数据库连接。当一个 Engine 被垃圾回收时,它的连接池不再被该 Engine 引用,并且假设它的任何连接都没有被检出,这个池和它的连接也将被垃圾回收,这具有关闭实际的效果数据库连接也是如此。但除此之外,引擎将保持打开的数据库连接,假设它使用 QueuePool 的通常默认池实现。

    引擎通常是预先建立并在应用程序的整个生命周期内维护的永久固定装置。它不打算在每个连接的基础上创建和处理;相反,它是一个注册表,它维护连接池以及有关正在使用的数据库和 DBAPI 的配置信息,以及每个数据库资源的某种程度的内部缓存。

    【讨论】:

      【解决方案2】:

      结合 SQLAlchemy,我使用SQLService 作为 SQLAlchemy 的会话管理器和 ORM 层的接口层,它很好地集中了 SQLAlchemy 的核心功能。

      这是我的中间件组件定义:

      class DatabaseSessionComponent(object):
          """ Initiates a new Session for incoming request and closes it in the end. """
      
          def __init__(self, sqlalchemy_database_uri):
              self.sqlalchemy_database_uri = sqlalchemy_database_uri
      
          def process_resource(self, req, resp, resource, params):
              resource.db = sqlservice.SQLClient(
                  self.sqlalchemy_database_uri, 
                  model_class=BaseModel
              )
      
          def process_response(self, req, resp, resource):
              if hasattr(resource, "db"):
                  resource.db.disconnect()
      

      在此处的 API 实例中对其进行实例化:

      api = falcon.API(
          middleware=[
              DatabaseSessionComponent(os.environ["SQLALCHEMY_DATABASE_URI"]),
          ]
      )
      

      【讨论】:

        猜你喜欢
        • 2016-01-18
        • 2011-11-05
        • 2021-06-15
        • 2016-08-07
        • 2011-05-15
        • 1970-01-01
        • 1970-01-01
        • 2018-11-05
        • 2010-10-27
        相关资源
        最近更新 更多