陈旧数据问题 Flask/SqlAlchemy
Issue with Stale data Flask/SqlAlchemy
我有以下设置 session.query() SqlAlchemy returns 陈旧数据:
Flask 上的 Web 应用程序 运行,带有 Gunicorn + supervisor。
其中一项服务是这样组成的:
app.py:
@app.route('/api/generatepoinvoice', methods=["POST"])
@auth.login_required
def generate_po_invoice():
try:
po_id = request.json['po_id']
email = request.json['email']
return jsonify(response=POInvoiceGenerator.get_invoice(po_id, email))
except Exception as ex:
app.logger.error("generate_po_invoice(): " + ex.message)
在另一个文件夹中我有数据库相关的东西:
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 背后的人。
我有以下设置 session.query() SqlAlchemy returns 陈旧数据:
Flask 上的 Web 应用程序 运行,带有 Gunicorn + supervisor。 其中一项服务是这样组成的:
app.py:
@app.route('/api/generatepoinvoice', methods=["POST"]) @auth.login_required def generate_po_invoice(): try: po_id = request.json['po_id'] email = request.json['email'] return jsonify(response=POInvoiceGenerator.get_invoice(po_id, email)) except Exception as ex: app.logger.error("generate_po_invoice(): " + ex.message)
在另一个文件夹中我有数据库相关的东西:
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 背后的人。