陈旧数据问题 Flask/SqlAlchemy

Issue with Stale data Flask/SqlAlchemy

我有以下设置 session.query() SqlAlchemy returns 陈旧数据:

Flask 上的 Web 应用程序 运行,带有 Gunicorn + supervisor。 其中一项服务是这样组成的:

在另一个文件夹中我有数据库相关的东西:

DatabaseModels(文件夹)

|-->Model.py

|-->Connection.py

这就是 connection.py 文件中包含的内容:

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

engine = create_engine(DB_BASE_URI, isolation_level="READ COMMITTED")
Session = scoped_session(sessionmaker(bind=engine))
session = Session()
Base = declarative_base()

那是 model.py 文件的摘录:

from DatabaseModels.Connection import Base
from sqlalchemy import Column, String, etc...

class Po(Base):
    __tablename__ = 'PLC_PO'

    id = Column("POId", Integer, primary_key=True)
    code = Column("POCode", String(50))
    etc...

那我还有一个文件POInvoiceGenerator.py 包含对数据库的调用以获取一些数据:

import DatabaseModels.Connection as connection
import DatabaseModels.model as model
def get_invoice(po_code, email):
    try:
        po_code = po_code.strip()
        PLCConnection.session.expire_all()
        po = connection.session.query(model.Po).filter(model.Po.code == po_code).first()

    except Exception as ex:
        logger.error("get_invoice(): " + ex.message)

在后续用户调用此服务时,有时我会开始收到类似这样的错误:无法在数据库中找到该特定代码的数据等等。比如数据是否过时等等。

我的第一个方法是将 isolation_level="READ COMMITTED" 添加到引擎声明中,然后创建一个作用域会话,但是过时的数据读取不断出现。

有没有人知道我的设置是否错误(会话和模型在多个方法和文件中重复使用)

提前致谢。

即使@TonyMountax 指出的 solution 似乎有效并让我发现了一些我对 SqlAlchemy 不了解的东西,最后我选择了不同的东西。

我发现 SqlAlchemy 建立的连接是持久的,因为它每次都是从连接池创建的,这不知何故导致数据陈旧。

我在我的代码中添加了一个 NullPool:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.pool import NullPool

engine = create_engine(DB_URI, isolation_level="READ COMMITTED", poolclass=NullPool)
Session = scoped_session(sessionmaker(bind=engine))
session = Session()

然后我为我进行的每个查询调用会话关闭:

session.query("some query..")
session.close()

这将导致 SqlAlchemy 每次都创建一个新连接并从数据库中获取新数据。

希望这是正确的使用方法并且可能对其他人有用。

实例化数据库连接的方式意味着它们会被下一个请求重用,并且它们还保留了上一个请求留下的一些状态。 SQLAlchemy 使用会话的概念与数据库进行交互,因此即使您碰巧执行了两次相同的查询,您的数据也不会在单个请求中突然改变。当您使用 ORM 查询功能时,这是有意义的。例如,如果您要在同一个会话中两次查询 len(User.friendlist),但在请求期间接受了好友请求,那么它仍将在两个位置显示相同的数字。

要解决此问题,您必须在第一次请求时设置会话,然后在请求完成后将其关闭。这样做并不简单,但已经有一个成熟的项目做到了:Flask-SQLAlchemy。它来自 Pallets,Flask 本身和 Jinja2 背后的人。