【问题标题】:sqlalchemy cursor error during yield_peryield_per 期间的 sqlalchemy 游标错误
【发布时间】:2012-08-27 07:41:34
【问题描述】:

我收到以下错误:

Traceback (most recent call last):
    main()
    for item in session.query(Item).yield_per(10):
    fetch = cursor.fetchmany(self._yield_per)
    self.cursor, self.context)
    l = self.process_rows(self._fetchmany_impl(size))
    row = self._fetchone_impl()
    self.__buffer_rows()
    self.__rowbuffer = collections.deque(self.cursor.fetchmany(size))
sqlalchemy.exc.ProgrammingError: (ProgrammingError) named cursor isn't valid anymore None None

我怀疑调用 session.commit() 会干扰 .yield_per

sessionmaker_ = sessionmaker(autocommit=False, autoflush=False, bind=engine)
session = scoped_session(sessionmaker_)

def foo(item):
  # DO something to the item 
  session.add(item)
  session.commit()

def main():
  for item in session.query(Item).yield_per(5):
    foo(item)

有什么想法吗?

【问题讨论】:

  • 您是否尝试像我们在#python 中建议的那样在您的 for 循环之后移动 .commit()?另外,你为什么要这样编辑你的回溯?删除信息很少有帮助。

标签: python sqlalchemy


【解决方案1】:

如果您没有从 DBAPI 游标中获取所有行,那么在该游标的连接上调用 commit() 通常是个坏主意。在这种情况下,psycopg2(我猜这是您使用的 DBAPI)无法在事务中维护命名游标(当您需要服务器缓冲行时使用的游标)的状态。

您绝对应该在这里更改的一件事是您提交的频率。理想情况下,在整个操作完成之前,您不会提交任何内容。会话将根据需要自动刷新数据(好吧,如果您打开了自动刷新,我建议这样做),或者您可以调用 flush() 来强制它,但这与实际提交事务无关。所有这些对 commit() 的调用都会使操作的效率大大降低,当然它会妨碍其他结果集的游标。如果你只是在循环的末尾放一个 commit(),那么你会同时解决这两个问题。

如果您仍然需要在整个操作完成之前提交,或者即使不需要,我更倾向于分块工作,而不是使用相当脆弱的 yield_per()。 http://www.sqlalchemy.org/trac/wiki/UsageRecipes/WindowedRangeQuery 的配方显示了一种方法。尽管 psycopg2 给了我们更多的余地,但 DBAPI 不太适合处理非常大的结果集。

【讨论】:

    【解决方案2】:

    上面的问题可以通过多一个会话来解决

    sessionmaker_ = sessionmaker(autocommit=False, autoflush=False, bind=engine)
    session = scoped_session(sessionmaker_)
    cool_session = scoped_session(sessionmaker_)
    
    def foo(item):
       # DO something to the item 
       session.add(item)
       session.commit()
    
    def main():
        for item in cool_session.query(Item).yield_per(5):
        item = session.merge(item, load=False)
        foo(item)
    

    【讨论】:

      【解决方案3】:

      另一个选项是在进入 sqlalchemy 版本时使用游标选项“WITH HOLD”: https://bitbucket.org/zzzeek/sqlalchemy/issues/3667/support-postgresqls-with-hold-cursor

      请注意 Scott 提到的关于 Postgres 在首次提交时实现游标的警告。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-01
        • 2020-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-24
        相关资源
        最近更新 更多