【发布时间】:2019-01-23 07:30:06
【问题描述】:
我有以下设置,在 session.query() SqlAlchemy 返回过时数据:
使用 Gunicorn + supervisor 在 Flask 上运行的 Web 应用程序。 其中一项服务是这样组成的:
-
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(文件夹)
|-->模型.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",然后创建一个作用域会话,但过时的数据读取不断出现。
是否有人知道我的设置是否错误(会话和模型在多个方法和文件中重复使用)
提前致谢。
【问题讨论】:
-
您能否清楚地添加您拥有的错误消息,显示错误行号和 SQLAlchemy 日志(如果有)。另外,如果您真的想捕获异常,请尝试显示它的类。最好先捕获 sqlachemy NoResultFound 和 StaleDataError,它们会显示具体的错误。
-
SqlAlchemy 中没有实际错误,只是我从数据库中获取的数据已经过时,在某种意义上,已经在外部修改并且已经在数据库中提交,但是当从 python 调用时,数据有点从 SqlAlchemy 的内存中读取
-
“数据有点从 SqlAlchemy 的内存中读取”:如果您首先“从数据库中读取”,然后不从实例中更改任何内容,则后续读取将从“内存”中读取:这个是 SqlAlchemy 的运行方式。请向我们展示一些错误日志,以便更好地了解您的问题。在您显示的代码中,根本没有任何修改,因此数据不会过时......除非您有另一个计算进程在您的 Flask 应用程序运行时更改数据库。
-
"除非您有另一个计算进程在您的 Flask 应用程序运行时更改数据库。" - 不幸的是,这就是正在发生的事情,烧瓶应用程序正在从一个可以从烧瓶应用程序本身外部修改的数据库读取,是一个由各种进程共享的数据库。
-
Web 是无状态/无事务的。如果你想处理你在之前的状态/交易中使用的相同数据,你必须确保它。例如这里首先捕获 NoResultFound (来自 sqlalchemy,使用 query.one() 而不是 query.first() )。然后,例如使用乐观锁定来了解数据是否已在其他地方更改(查看docs.sqlalchemy.org/en/latest/orm/…)。
标签: python flask sqlalchemy gunicorn supervisord