ZODB存储
ZODB存储
http://www.315ok.org/blogfolder/103
http://www.315ok.org/logo.png
ZODB存储
ZODB存储
当用Zope做开发时,开发人员可以在数据存储上获得很大解放。Zope为每一个到来的请求开启一个新的transaction.如果错误发生(如不可捕获的exception 发生),这个事务被回滚,没有任何修改被写入。如果没有错误发生,这个transaction事务被提交,任何对 链接到ZODB对象路径的所有对象的修改被保存。
[size=5]事务[/size]
Transactions 被transaction module管理。事务也可能被手动开启和结束,但通常需要的操作只是设置一个savepoint。一个savepoint就像一个子事务,它被要求在某些操作之前完成,它也对程序释放内存有帮助通过写部分事务到磁盘cache。
一个对象要保存,它必须或者是原始内建的类型(如一个整数或字符串),或者它的类扩展自persistence.Persistent基类。
The ZODB will automatically detect when a persisted object has been changed.Those changes will be saved when the transaction is committed. The exception is that if an object has a standard list or dict as an attribute, and a value in that list or dict is changed, Zope will not be able to detect it. If no other changes took place for that object, the changes may be lost.To explicitly tell the ZODB to persist an object, you can set the _p_changed property to True:
For example, BTrees.IOBTree.IOSet is an unordered set with integer keys, while BTrees.OIBTree.OIBTree is a mapping with object keys, and integer values. See Interfaces.py in that module for more information.Finally, it is possible to use volatile attributes, which are explicitly not saved. They will only remain as long as the object is in memory. Since there is no guarantee of how long an object will remain in memory until it is ghosted by the ZODB, you can never rely on volatile attributes being there, but they are sometimes useful as a simple cache.
Volatile attributes have names beginning with _v_. They must be used defensively:
[size=5]事务[/size]
Transactions 被transaction module管理。事务也可能被手动开启和结束,但通常需要的操作只是设置一个savepoint。一个savepoint就像一个子事务,它被要求在某些操作之前完成,它也对程序释放内存有帮助通过写部分事务到磁盘cache。
Note that a very small number of functions require a savepoint to run in combination. Most commonly, if you need to use the manage_cutObjects() and manage_pasteObjects() methods from OFS.CopySupport in the same transaction, you may need to place a savepoint between them.设置一个savepoint, use:
import transaction savepoint = transaction.savepoint()现在可以通过调用savepoint.rollback() 来回滚sub-transaction。如果你只是想释放内存,用下面的优化的savepoint:
transaction.savepoint(True)这将返回一个值,但回滚一个优化的savepoint将导致一个错误。如果需要中断一个事务,你应该甩出一个unhandled exception。注意ZODB错误操纵机制用一个特别的叫ConflictError的exception来表达多个线程修改同一对象时引发的写冲突。一个 conflicted transaction总是被自动解决,但你必须让这个exception不可捕获,以便允许Zope来重试先前失败的事务。
Do not use a bare try…except clause around code that could cause a ZODB write, and thus could raise a ConflictError. Always let a ConflictError go unhandled. Of course, you should try to avoid bare excepts in general.为确保ConflictErrors 不被抑制,你经常可以看到类似下面的代码:
from ZODB.POSException import ConflictError try: # some unpredictable operation that may cause a write except ConflictError: raise except: # Swallow other errors or handle in some other way[size=5]对象存储[/size]
一个对象要保存,它必须或者是原始内建的类型(如一个整数或字符串),或者它的类扩展自persistence.Persistent基类。
Take a look at the persistence module, in particular interfaces.py,if you want to know the gritty details of object persistence.所有Plone内容类型都扩展自这个基类。The base classes we will use in Chapter 10 to build new content types properly derive from Persistent as well.To be saved, an object must be connected to the ZODB object graph by being set as an attribute of another persistent object. This is what happens when a content object is added to a folderish parent in Plone, for example. When an attribute is accessed later, the ZODB will transparently load the associated object from disk if necessary.
The ZODB will automatically detect when a persisted object has been changed.Those changes will be saved when the transaction is committed. The exception is that if an object has a standard list or dict as an attribute, and a value in that list or dict is changed, Zope will not be able to detect it. If no other changes took place for that object, the changes may be lost.To explicitly tell the ZODB to persist an object, you can set the _p_changed property to True:
>>> someobj.somedict['key1'] = "new value" >>> someobj._p_changed = TrueAlternatively, you can use either of the two classes: persistent.dict.PersistentDict or persistent.list.PersistentList. These act exactly like standard dicts and lists, but derive from Persistent, and will set _p_changed as necessary:
>>> from persistent.dict import PersistentDict >>> someobj.somedict = PersistentDict() >>> someobj.somedict['key1'] = "new value"The PersistentDict, and PersistentList types are not recommended for large data sets (hundreds of items or more). This is because each time the ZODB saves an object, it will essentially write out a new copy of it (at least with the default File Storage). Every time an item in one of these data structures is changed, the entire dict or list is versioned.
Writing a new copy of the object while saving it allows the Undo tab in the ZMI to work. It also makes the ZODB very fast. On frequently changing sites, the ZODB should be packed regularly. You can do so from the Maintenance control panel in Plone, or the Control_Panel in the ZMI.In Chapter 16, we will look at how to automate this process.For large data sets, the BTrees module provides several optimized data structures,which do not suffer from this problem. They come in sets (IOSet, OOSet, OISet,IISet), sorted sets (IOTreeSet, OOTreeSet, OITreeSet, IITreeSet), and mappings (IOBTree, OOBTree, OIBTree, IIBTree), designed for integer or object keys or values.
For example, BTrees.IOBTree.IOSet is an unordered set with integer keys, while BTrees.OIBTree.OIBTree is a mapping with object keys, and integer values. See Interfaces.py in that module for more information.Finally, it is possible to use volatile attributes, which are explicitly not saved. They will only remain as long as the object is in memory. Since there is no guarantee of how long an object will remain in memory until it is ghosted by the ZODB, you can never rely on volatile attributes being there, but they are sometimes useful as a simple cache.
Volatile attributes have names beginning with _v_. They must be used defensively:
>>> someobj._v_saved = expensive_operation() >>> # do something else for a while >>> saved = getattr(someobj, '_v_saved', None) >>> if saved is None: # in case we lost it ... >>> saved = expensive_operation()