由于查询调用的自动刷新导致 SQLAlchemy OperationalError

Posted

技术标签:

【中文标题】由于查询调用的自动刷新导致 SQLAlchemy OperationalError【英文标题】:SQLAlchemy OperationalError due to Query-invoked autoflush 【发布时间】:2017-04-03 15:11:16 【问题描述】:

我在通过 SQLAlchemy 创建和访问的数据库中有一个表:

我使用 Flask-SQLAlchemy 向其中添加一条记录,如下所示:

...
content = request.form['content']
date = datetime.today()
post = Post(date, content)
db.session.add(post)
db.session.commit()
...

这条记录被添加到表中。执行该代码后,我立即查询另一个表:

userID = session['userID']
posts = db.session.query(Post).filter_by(userID=userID).count()

但是我在查询过程中收到错误:

OperationalError:(由于查询调用自动刷新而引发; 如果发生此刷新,请考虑使用 session.no_autoflush 块 过早地)(_mysql_exceptions.OperationalError)(1292,“不正确 日期值:第 1 行的“日期”列的“11/20”)[SQL:u'UPDATE 帖子设置日期=%s WHERE posts.id = %s'] [参数:(('11/20', 1L))]

为什么我在将记录添加到表格时已经指定了帖子的日期,但它正在更新?另外这个错误的原因是什么?谢谢。

编辑:

这就是表格模型的样子:

class Post(db.Model):

  __tablename__ = 'posts'

  id = db.Column(db.Integer, primary_key=True)
  content = db.Column(db.String(500))
  date = db.Column(db.Date, nullable=False)

  def __init__(self, id, content, date):
      self.id = id
      self.content = content
      self.date = date

【问题讨论】:

Pav 我删除了我的答案,你说得对,这无关紧要。问题是我们必须遗漏一些细节(可能还有更多代码?)才能深入了解。如果我想出任何其他想法,我会发布一个新的答案。 @PavSidhu 你纠正了mysql异常,好像和第一个代码块有关 如果你放弃filter_by会发生什么? 【参考方案1】:

Stephane 是对的,您向模型传递了错误的类型,要么传递 datetime.date 对象,要么更改模型的定义。至于问题的第一部分,我建议阅读有关sessions and flushing 的内容。这很重要:

跟踪由 Session 维护的对象的所有更改 - 在再次查询数据库或提交当前事务之前,它会刷新对数据库的所有挂起更改。

因此,通过创建 post 对象并将其添加到会话中,您只进行了待处理的更改,但此时还没有与数据库进行通信。 flush() 会发生这种情况,您可以手动或自动调用它,例如通过调用 commit()。

(顺便说一句。您不需要为模型创建自己的 init 方法,请参阅http://docs.sqlalchemy.org/en/latest/orm/tutorial.html#adding-and-updating-objects)

【讨论】:

【参考方案2】:

date = datetime.today() 返回一个日期时间对象(日期和时间)

但是Post模型的日期属性是一个db.Date(没有时间的日期)

试试:

  from datetime import date

  ...

  content = request.form['content']

  date = date.today()    #inject a Date object rather than a Datetime

或:

  class Post(db.Model):     #modify Post schema

  ...

     date = db.Column(db.TIMESTAMP, nullable=False)

【讨论】:

【参考方案3】:

此错误可能由另一个查询引起, 即使你解决了它,如果你不回滚以前的会话错误仍然会发生异常

你可以捕获异常并回滚事务

通常在我的烧瓶应用程序中,我在请求结束时提交会话

@app_instance.after_request
def after(response):
    try:
        # commit transaction
        db.session.commit()
    except Exception:
        db.session.rollback()
        raise

    return response

【讨论】:

以上是关于由于查询调用的自动刷新导致 SQLAlchemy OperationalError的主要内容,如果未能解决你的问题,请参考以下文章

使用 SQLAlchemy 刷新物化视图

从 PendingRollbackError 中恢复并允许后续查询

Elasticsearch在操作数据后不能立即查询到数据

由于使用自动增量添加到表中,如何使用更新的数据刷新 C# DataTable?

flask-sqlalchemy数据库自动更新

快速入门流行ORM框架~Flask-SQLAlchemy