保存点允许数据管理器将工作保存到其存储而无需提交完整的事务。“”保存点对于释放内存也很有用,否则这些内存将用于保持事务的整个状态。
根据非常有启发性的文章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的工作方式与bsddb3.db.Db.sync
相同。调用Db.sync()
时,将刷新数据库,您可以观察它。但是当设置保存点时,显然数据库和tmp文件都不会增长或者大小不变transaction.commit()
。
我真的很困惑:
设置保存点后实际发生了什么?
与提交/刷新数据库有什么不同?
如果“要临时存储在磁盘上的数据”,保存点在哪里写入数据?
我可以依靠保存点来实现“免费记忆”吗?
答案 0 :(得分: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()
对象,出于安全原因,该对象是在 unlinked 状态下创建的;文件存在,但目录条目在创建时立即清除。因此,无法从ZODB流程外部看到此文件。
完整提交将数据移动到实际的ZODB数据库中并完成事务。
答案 1 :(得分:0)
保存点的主要用途是释放内存并将事务相关数据从内存存储到磁盘 - 尤其是对于大型事务和大量修改过的数据。