Plone技术资料

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 6856|回复: 0

ZCA在Plone应用之二:ZODB中的Persistence

[复制链接]
发表于 2012-2-25 15:11:34 | 显示全部楼层 |阅读模式
ZODB中的Persistence
       当用Zope工作时,开发者完全不用担心persistence。Zope为每一个请求开启一个新的事务。如果有错误发生(那就是说,一个uncaught的异常被抛出),该事务被回滚,并且没有更新写入。如果没有错误发生,该事务会被提交,同时对于一个任何关联于ZODB对象图的对象的变化会被保存。
事务
       事务是由事务模块管理。手工开启和结束事务是可能的,但是在实际中,我们在测试工作之外唯一做的操作是设置一个保存点。一个保存点就像是一个子事务。在一些操作之前,它是被要求的。但是,对一个磁盘缓存,通过编写特定的事务,它也能够帮助释放内存。
笔记:只有很少的函数在运行前会要求设置一个保存点。大多数情况下,如果在一个事务中,你需要使用来自于OFS.CopySupport 中的manage_cutObjects() 和manage_pasteObjects() 方法,你或许需要在它们之间放置一个保存点。
为了设置一个保存点,使用:
  1. import transactionsavepoint = transaction.savepoint()
复制代码
  
       现在调用savepoint.rollback()来回滚这个子事务是可能的。如果我们仅仅对释放内存感兴趣,我们可以使用一个optimistic 保存点:
transaction.savepoint(optimistic=True)
这个仍会返回一个值,但是回滚一个optimistic保存点会返回一个错误。
如果我们需要退出一个事务,我们可以抛出一个不被处理的异常。注意到,当多个线程尝试修改同一个对象时,ZODB的错误处理机制使用一个被称为ConflictError的异常来处理写冲突。一个冲突的事务几乎可以自动解除,但是我们必须让此类异常不被捕获,允许Zope重试那个失败掉的事务。
笔记:不要在代码附近只用一个会导致ZODB写操作的try···except语句,因为这样可能会引起ConflictError。要使ConflictError不被捕获。当然,在任何情况下,你应该避免bare异常。
为了确保ConflictErrors不被吞噬,有时我们会使用如下代码:
  1. from ZODB.POSException import ConflictErrortry:# some unpredictable operation that may cause a writeexcept ConflictError:raiseexcept Exception:# Swallow other errors or handle in some other way
复制代码
Object persistence
       对于一个持续性的对象,它一定要么是原始的(例如一个整数或者一个字符串),要么是一个继承于persistence.Persistent的类。所有的Plone内容类型最终继承于这个基类。我们会在第十章(定制化内容类型)中使用这个基类来创建新的内容类型,当然也是继承于Persistent。
       为了被保存,一个对象必须连接至ZODB对象图,通过被设置为另外一个persistent对象的一个属性或者被放置进一个persistent映射。在Plone中,当一个内容对象被添加至一个folderish父文件夹,这就是所发生的。之后,当一个属性或一个映射值被访问时,ZODB会在必要的时候,显示地从磁盘加载相关联的对象。
       当一个persisted对象被改变的时候,ZODB将会自动检测。当事务提交完后,那些改变会被保存。而异常就是当一个对象有Python列表或字典为属性,同时,列表或字典中的值被改变,Zope将不能够探测到它。如果对于那个对象,没有其他更新发生,那么这些改变将不被保存。
       为了明确的告诉ZODB去persist一个对象,我们可以设置_p_changed属性为True:
  1. >>> someobj.somedict['key1'] = "new value">>> someobj._p_changed = True
复制代码
或者,我们可以使用类persistent.mapping.PersistentMapping或persistent.list.PersistentList。这些操作就像标准的列表和字典,但它们继承于Persistent,所以需要设置_p_changed:
  1. >>> from persistent.mapping import PersistentMapping>>> someobj.somedict = PersistentMapping()>>> someobj.somedict['key1'] = "new value"
复制代码

      类型PersistentMapping和PersistentList不建议在大的数据集(成百的实体或者更多)上使用。这是因为每次ZODB保存一个对象时,它会写出一份新的拷贝来。每次当这些数据结构中的一个项目被改变时,整个字典或列表被升一个版本。
       笔记:At least with the default ZODB FileStorage,which stores the database in the Data.fs file. This is what allows the Undo tabin the ZMI to work. It also makes the ZODB very fast. On frequently changingsites, the ZODB should be packed regularly. You can do so from the Maintenancecontrol panel in Plone, or the Control_Panel in the ZMI. In Chapter 17, Settingup a Production Server, we will look at how to automate this process.
       对于大的数据集,BTrees模块提供一些优化的数据结构,这些数据结构将不会遭遇此类问题。They comein sets (IOSet, OOSet, OISet, IISet), sorted sets (IOTreeSet, OOTreeSet, OITreeSet, IITreeSet) andmappings (IOBTree, OOBTree, OIBTree, IIBTree), designed for integer orobject keys or values。例如,BTrees.IOBTree.IOSet是一个带有整数键的无序集,而BTrees.OIBTree.OIBTree是一个带有对象键及整数值的映射。查看BTrees.Interfaces模块获取更多的信息。
       笔记:The most common type of object key in an OIBTree or OOBTree is astring. For example, Plone's Folder type stores its children in an OOBTree withstrings keys and content object values. It is generally advisable to stick to usingprimitives as object keys。
最后,使用从来不被保存的volatile属性是可能的,而只有当它们在内存中时才存在。一个对象要在内存中驻留多长时间是没有保证的,直到ZODB把它ghosted掉。我们决不能依赖那些内存中的volatile属性(或者当它们已被删除后,去依赖它们),但有时候它们作为一个缓存,还是很有用处的。
       Volatile属性名字以_v_开头,它们必须以defensively地方式使用:
  1. >>> 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()
复制代码

ZODB BLOBs
       自version3.8以来,ZODB已经支持Binary Large Objects (BLOBs)。BLOBs被高效的用来存储、管理和serveup大的数据,例如向Plone site上传文件夹。当BLOB资源被要求时(例如,一个用户想从Plone site下载文件),Zope将会使用一个单独的从磁盘直接读取数据的线程,为该用户stream这个目标数据,并提交给Zope的主线程来处理这个请求。Plone4的镜像和文件内容类型现在已将它们的数据存在BLOBs中。
       当使用默认的FileStorageZODB的后台,BLOBs存储在由Zope管理的目录下的文件中。在一个Plone标准的buildout中,这个通常是var/blobstorage/。
       以custom content types的方式来使用BLOBs是比较容易的,这一点我们在下一章节中会看到。
       笔记:InPlone development, it is relatively uncommon to use BLOB objects directly. At ahigh level, you store a ZODB.blob.Blob object in the ZODB like any otherpersistent object, and feed it data using the consumeFile() method. To read theBLOB's data, use the open() method, which returns a file-like object. Take alook at ZODB. interfaces.IBlob for more details.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|Plone技术资料 ( 湘ICP备14006519号-1 )

GMT+8, 2019-11-18 10:05 , Processed in 0.047217 second(s), 17 queries , Gzip On.

Powered by Plone! X3.4

© 2001-2019 Plone.org.

快速回复 返回顶部 返回列表