我在session.query()SqlAlchemy上返回过时数据的设置如下:
在带有Gunicorn +主管的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)
在另一个文件夹中,我有与数据库相关的内容:
数据库模型(文件夹)
|-> 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”,然后创建一个有作用域的会话,但是陈旧的数据读取仍在继续。
是否有人知道我的设置是否错误(会话和模型在多个方法和文件之间重用)
谢谢。
答案 0 :(得分:0)
即使@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每次创建一个新连接并从数据库中获取新数据。
希望这是使用它的正确方法,并且可能对其他人有用。
答案 1 :(得分:0)
实例化数据库连接的方式意味着它们将被下一个请求重用,并且它们在上一个请求中还有一些状态。 SQLAlchemy使用会话的概念与数据库进行交互,因此即使您两次执行相同的查询,您的数据也不会在单个请求中突然改变。使用ORM查询功能时,这很有意义。例如,如果您在同一会话中两次查询len(User.friendlist)
,但是在请求过程中接受了好友请求,那么在两个位置它仍将显示相同的数字。
要解决此问题,必须在第一个请求上建立会话,然后在请求完成后将其拆除。这样做并非易事,但是已经有一个完善的项目已经完成:Flask-SQLAlchemy。来自Pallets,Flask本身和Jinja2背后的人。