陈旧数据烧瓶/ SqlAlchemy的问题

时间:2018-08-16 10:53:30

标签: python flask sqlalchemy gunicorn supervisor

我在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”,然后创建一个有作用域的会话,但是陈旧的数据读取仍在继续。

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

谢谢。

2 个答案:

答案 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背后的人。

相关问题