我需要通过SQLAlchemy插入/更新批量行。并获得插入的行。
我尝试使用session.execute:
>>> posts = db.session.execute(Post.__table__.insert(), [{'title': 'dfghdfg', 'content': 'sdfgsdf', 'topic': topic}]*2)
>>> posts.fetchall()
ResourceClosedError Traceback (most recent call last)
使用引擎:
In [17]: conn = db.engine.connect()
In [18]: result = conn.execute(Post.__table__.insert(), [{'title': 'title', 'content': 'content', 'topic': topic}]*2)
In [19]: print result.fetchall()
ResourceClosedError: This result object does not return rows. It has been closed automatically.
相同的响应是对象已自动关闭。怎么预防呢?
答案 0 :(得分:9)
第一个答案 - 关于“防止自动关闭”。
SQLAlchemy使用insert运行DBAPI execute()或executemany(),不执行任何选择查询。
所以你得到的例外是预期的行为。在执行插入查询后返回的ResultProxy对象包装了不允许在其上执行.fetchall()
的DB-API游标。一旦.fetchall()
失败,ResultProxy会向用户返回您看到的异常。
插入/更新/删除操作后,您可以获得的唯一信息是受影响的行数或自动增量后的主键值(取决于数据库和数据库驱动程序)。
如果您的目标是接收此类信息,请考虑检查ResultProxy methods and attributes,如:
第二个答案 - 关于“如何批量插入/更新并获得结果行”。
使用DBAPI进行单个插入查询时无法加载插入的行。您用于批量插入/更新的SQLAlchemy SQL Expression API也不提供此类功能。 SQLAlchemy运行DBAPI executemany()调用并依赖于驱动程序实现。有关详细信息,请参阅this section of documentation。
解决方案是设计您的表格,使每条记录都具有识别记录的自然键(以独特方式标识记录的列值组合)。因此,插入/更新/选择查询将能够以一条记录为目标。 在完成之后,可以先进行批量插入/更新,然后通过自然键进行选择查询。因此,您不需要知道自动增量的主键值。
另一种选择:可能是你可以使用SQLAlchemy Object Relational API来创建对象 - 然后SQLAlchemy可能会尝试优化insert以使用executemany为你做一个查询。在使用Oracle DB时,它对我有用。 开箱即用的更新不会有任何优化。检查this SO question以获得有效的批量更新提示