9

我需要通过 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.

同样的响应是对象已自动关闭。如何预防?

4

1 回答 1

9

第一个答案-关于“防止自动关闭”。

SQLAlchemy 使用 insert 运行 DBAPI execute() 或 executemany() 并且不执行任何选择查询。所以你得到的例外是预期的行为。执行插入查询后返回的 ResultProxy 对象包装了不允许对其进行操作的 DB-API 游标.fetchall()。一旦 .fetchall()失败,ResultProxy 会向用户返回您看到的异常。

插入/更新/删除操作后您可以获得的唯一信息是受影响的行数或自动递增后的主键值(取决于数据库和数据库驱动程序)。

如果您的目标是接收此类信息,请考虑检查ResultProxy 方法和属性,例如:

  • .inserted_primary_key
  • .last_inserted_pa​​rams()
  • .lastrowid
  • ETC

第二个答案 - 关于“如何进行批量插入/更新并获取结果行”。

使用 DBAPI 进行单次插入查询时,无法加载插入的行。您用于进行批量插入/更新的 SQLAlchemy SQL 表达式 API 也不提供此类功能。SQLAlchemy 运行 DBAPI executemany() 调用并依赖于驱动程序实现。有关详细信息,请参阅文档的此部分

解决方案是设计您的表,使每条记录都具有识别记录的自然键(以唯一方式识别记录的列值的组合)。因此插入/更新/选择查询将能够针对一条记录。完成后,可以先进行批量插入/更新,然后按自然键进行选择查询。因此,您不需要知道自动递增的主键值。

另一种选择:可能您可以使用SQLAlchemy 对象关系 API来创建对象 - 然后 SQLAlchemy 可能会尝试优化插入,以便为您执行一个查询。它在使用 Oracle DB 时对我有用。开箱即用的更新不会有任何优化。检查这个 SO question以获得有效的批量更新想法

于 2013-01-17T21:20:20.327 回答