我收到以下错误:
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)
任何想法?
解决方法
如果没有从DBAPI游标中获取所有行,那么在该游标的连接上调用commit()通常是一个坏主意.在这种情况下,psycopg2(我猜测这是您所在的DBAPI)无法维护命名游标的状态(这是当您需要服务器缓冲行时)在事务中使用的状态.
你应该在这里改变一件事是你提交的频率.理想情况下,在整个操作完成之前,您不会提交任何内容.会话将根据需要自动刷新数据(如果您打开自动冲洗,我建议您),或者您可以调用flush()来强制它,但这与实际提交事务无关.所有这些对commit()的调用将使操作的效率要低于它所必须的效率,当然它会阻碍其他结果集的游标.如果你刚刚把一个commit()放在你的循环的末尾,那么你可以一次解决这两个问题.
如果您仍然需要在整个操作完成之前提交,或者即使不是这样,那么我更喜欢使用块而不是使用yield_per(),这是非常脆弱的. http://www.sqlalchemy.org/trac/wiki/UsageRecipes/WindowedRangeQuery的食谱显示了一种方法.尽管psycopg2给我们一个更大的回旋余地,但DBAPI并不适合处理非常大的结果集.