SQLAlchemy、Flask 和交叉污染?

use*_*855 3 python sqlalchemy flask

我接手了一个flask应用程序,但它没有使用flask-sqlalchemy插件。我很难理解它是如何设置的。

它有一个database.py文件。

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session, Session


_session_factory = None
_scoped_session_cls = None
_db_session: Session = None


def _get_session_factory():
    global _session_factory
    if _session_factory is None:
        _session_factory = sessionmaker(
            bind=create_engine(CONNECTION_URL)
        )
    return _session_factory


def new_session():
    session_factory = _get_session_factory()
    return session_factory()


def new_scoped_session():
    global _scoped_session_cls
    if _scoped_session_cls is None:
        session_factory = _get_session_factory()
        if not session_factory:
            return
        _scoped_session_cls = scoped_session(session_factory)
    return _scoped_session_cls()


def init_session():
    global _db_session

    if _db_session is not None:
        log.warning("already init")
    else:
        _db_session = new_scoped_session()
    return _db_session


def get_session():
    return _db_session
Run Code Online (Sandbox Code Playgroud)

我们启动 Flask 应用程序,它会调用database.init_session(),然后每当我们想要使用它调用的数据库时database.get_session()

这是与数据库交互的正确/安全方式吗?如果两个请求同时由不同的线程处理,会发生什么情况?这是否会导致两者使用同一会话的交叉污染

Yaa*_*ler 5

为了解释代码中发生的情况,让我们首先深入了解如何sqlalchemy连接到数据库:

1. 创建引擎

此时,您可以直接连接数据库:

engine = create_engine(...)

with engine.connect() as connection:
    result = connection.execute(...)
Run Code Online (Sandbox Code Playgroud)

请注意,在事务完成/连接关闭之前,不能保证在此连接上下文中创建/更改的对象共享连接上下文之外的状态。

要执行更复杂的查询(例如:选择和插入的混合),您将需要使用会话。

2. 开启会话

3. 检查上面的代码:

上面代码的目的过于简单化,是通过get_session().

最初,这将返回None,因为这是 的值_db_session

因此,您必须调用init_session()它将创建返回会话所需的各种对象get_session()

以下是其中发生的事情init_session()

  1. 调用new_scoped_session()将返回session_factory
  2. _get_session_factory()创建的调用- session_factory> 请注意它如何engineCONNECTION_URL
  3. scoped_session(session_factory)创建范围会话并分配给 的调用_scoped_session_cls注意:这与常规会话非常相似,只是更加隔离(并且安全)。

许多复杂性与状态缓存有关。本质上,该代码正在执行以下操作:

Session = sessionmaker(engine)
Run Code Online (Sandbox Code Playgroud)

我希望这可以帮到你。祝你好运!