1

根据ZODB 文档

保存点允许数据管理器在不提交完整事务的情况下将工作保存到其存储中。” “保存点对于释放内存也很有用,否则这些内存将用于保持事务的整个状态。

根据非常有指导意义的文章When to commit data in ZODB (Martijn Pieters):

...在整个交易过程中,您可以要求将数据临时存储在磁盘上。[...]
保存点所做的一件事是调用 ZODB 缓存的垃圾收集,这意味着当前未使用的任何数据都将从内存中删除。

问题是,我需要在一个事务中存储很多项目,如下所示:

for i, item in enumerate(aLotOfItems):
    database[i]=item
    if i % 10000 ==0:
        transaction.savepoint(True)
transaction.commit()

我有点期望 transaction.savepoint 以与 .savepoint 相同的方式工作bsddb3.db.Db.sync。当Db.sync()被调用时,数据库被刷新,你可以观察它。但是,当设置保存点时,显然数据库和 tmp 文件都不会增长或更改大小 untill transaction.commit()

我真的很困惑:

  • 设置保存点时实际发生了什么?

  • 它与提交/刷新数据库有什么不同?

  • 如果“数据要临时存储在磁盘上”,保存点将数据写入到哪里?

  • 我可以指望保存点来真正“释放内存”吗?

4

2 回答 2

7

保存点最初的主要用途是能够回滚事务的一部分

假设你想接受大量的日志条目,但需要将它们批量处理到数据库中:

for batch in per_batch(log_entries):
    sp = transaction.savepoint()
    try:
        process_batch(batch)
    except BatchFailedException:
        sp.rollback()
        transaction.commit()
        raise

现在事务已提交,除了最后一批已回滚。

这就是使用保存点的最初原因。设置保存点具有触发 ZODB 缓存垃圾收集运行的副作用。

ZODB 保存最近访问的对象的缓存。这包括在当前事务中实际上没有改变的对象;您只是从数据库中检索它们,使用它们的数据,然后停止直接引用它们。ZODB 存储一个对象图;一个对象引用其他对象,而后者又引用其他对象。这些对象中的每一个(如果它们从Persistent基类继承)都是单独的 ZODB 记录。当你遍历图时,这些对象都被加载到内存中。

GC 运行会再次从内存中清除它们,前提是它们没有更改。再次遍历对象图会将它们再次加载到内存中,但在保存点期间清除它们可以节省内存。

保存点数据本身存储在磁盘上的TmpStorage文件中,在您的TEMP目录中。这使用了一个tempfile.TemporaryFile()对象,出于安全原因,该对象在未链接状态下创建;该文件存在,但目录条目在创建时立即被清除。因此,您无法从 ZODB 进程之外看到此文件。

完全提交将数据移动到实际的 ZODB 数据库中并最终确定事务。

于 2013-10-31T16:30:34.793 回答
0

保存点的主要用途是释放内存并将与事务相关的数据从内存存储到磁盘 - 特别是对于大型事务和大量修改数据。

于 2013-10-31T15:46:38.977 回答