`
fulerbakesi
  • 浏览: 562231 次
文章分类
社区版块
存档分类
最新评论

鲁棒的持久层设计

 
阅读更多
一个持久层封装了使对象持久化的行为,或者说从(或者向)永久存储中读取、写入、
删除对象。一个鲁棒的持久层应该支持:
1 多种持久机制。一个持久机制是一种可以永久保存对象使其可以在以后被更新、获取和
删除的技术。可能的持久机制包括文本文件、关系数据库、对象-关系数据库、层次数
据库(hierarchical database)、网络数据库和对象数据库。在本文中,主要讨论集中在针
对关系数据库的持久层方面,另外,通过使用微软的OLE-DB 技术也可以支持多种持
久机制。
2 对持久机制进行完整的封装。理想情况下,只需要发送save、delete、retrieve消息给一
个对象,就可以保存、删除或者获取它,持久层完成其它的工作。进一步讲,除了对已
知异常的处理,不必写任何其它关于持久层的代码。
3 基于条件的多对象操作。因为一次返回多个对象是很常见的,例如一个报表或者一次
用户定制的搜索,一个鲁棒的持久层必须可以支持根据一定条件同时返回多个对象的情
况。对于根据一定条件删除多个对象也同样应该支持。
4 基于关联的多对象操作。就象在关系数据库中可以进行关联的删除、获取和保存一样,
这些操作也应该可以针对对象。一个最好的例子就是一个Invoice 对象拥有多个
LineItem对象实例,在获取、删除或者保存一个Invoice对象的时候,应该自动的获取、
删除或者保存它的LineItem对象。
5 事务。与需求3相关的是支持事务,也就是针对多个对象的一组操作。一个事务应该由
保存、获取和/或删除的任意组合组成。事务可以是简单的,一种“要么全部要么没有”
的方式,操作必须全部成功或者全部回滚(取消)。或者也可以是嵌套的,在外层的事
务失败的时候,嵌套的事务仍然提交而不回滚。事务可以是短期的,只运行千分之一秒,
或者是长期的,花费几小时、几天、几周甚至几个月。
Visit WWW.AmbySoft.com for more White Papers on Object-Oriented Development
5
6 扩展性。你可以增加新的类或者属性,并且能容易的变更持久机制(例如从一个厂商的
产品移植到另一个产品,或者是升级)。换句话说,持久层必须可以足够灵活以允许应
用程序开发者和持久机制管理员做他们需要做的事。
7 对象标识符。对象标识符(Ambler, 1998c),或者缩写为OID,是一个属性,通常是一
个编号,用来唯一标识一个对象。OID 是关系理论中在一个表中唯一标识一行的列—“键
(key)”的等价物。OID可以通过GUID和UUID等方法实现。
8 组合键。传统的数据库结构经常使用由两列或多列构成的组合键来唯一标识一行。尽管
这样使数据库结构和持久层都变得复杂(Ambler, 1998c),但不幸的是现实即是如此,
我们不得不与这些旧的设计打交道。
9 多键。传统的数据库结构中,一个表中经常包括多个键(表可以有一个主键和多个次键)。
持久层应该利用这些额外的键带来的性能方面的好处。
10 游标。一个支持从一个命令获取多个对象的持久层,也应该支持获取游标。这是一个效
率问题:你是否希望用户一次只从持久机制的百万个person 对象中获得一个呢?当然
不。游标就是关系世界中这样的一个有趣概念。一个游标是一个到持久机制的逻辑连接,
从这个连接,可以可控的获取对象,通常一次多个。这样常常比一次返回上百个甚至上
千个对象要有效率,因为用户可能并不立即需要所有的这些对象(可能通过一个列表翻
滚)。
11 评估结果集大小。在执行一个多对象操作的时候,你希望先确定有多少持久对象会被
这个操作影响。例如,一个用户可能输入一个蹩脚的可能导致几千条结果的查询条件。
你应该希望在执行操作前告诉他以使用户决定是否重新定义条件。
12 代理。对游标的一个补充就是“代理”。代理代表另外一个对象,但是又不会导致与被
代表的对象同样的开销。代理只包括足以让计算机和用户标识它的信息,而没有其它的
内容。例如,一个person 对象的代理包含它的OID,因此应用程序可以标识它,也包
含姓、名以便用户可以分辨出这个代理代表的是谁。代理通常在用户在一个显示出来的
结果集列表中选择一条或者两条的时候使用。在用户从列表中选择了代理对象的时候,
真正的,比代理对象大的对象被自动的从持久机制中获取出来。例如,完整的person
对象可能包括地址和个人照片。通过使用代理,你不必在网络上传递每个person 对象
的所有信息,而只传递那些将被实际用到的。这也被称为lazy read。
13 记录。目前市面上大量的报表工具都是以数据库记录作为输入,而不是对象。如果你所
在的组织正在一个面向对象的应用程序中使用这样的工具进行报表处理,你的持久层应
该支持在retrieve请求后返回记录的能力。这样可以避免数据库记录转换成对象后再转
换回记录产生的开销。
14 多种体系结构。当计算从集中的主机迁移到两层的客户机/服务器结构再到多层结构再
到分布式对象的时候,持久层应该可以支持这些变化。要点是你必须假设在某些时候持
久层可能存在于一个可能非常复杂的环境中。
15 不同数据库版本和厂商。你会升级你的数据库或者移植到其它的数据库。持久层应该
支持在不对应用程序造成影响的前提下,简单的变更持久机制。因此,持久层应该支持
多种数据库版本和厂商。
16 多连接。多数组织使用多种来自不同厂商的数据库,而这些数据库又会被同一个对象应
用程序访问。这等于说要求持久层应该可以对每种持久机制都提供多个、同时的连接。
Visit WWW.AmbySoft.com for more White Papers on Object-Oriented Development
6
即使一些象从某个持久机制拷贝一个对象到另外一个这样简单的事情,比如从一个中心
数据库拷贝到本地数据库,都至少同时需要两个连接,每个数据库一个。
17 连接池。持久层应该可以共享数据库的连接,尤其是如果将被部署为应用服务器的一部
分的时候。在这种情况下,几百个甚至几千个客户会连接到一个应用服务器。因为每个
连接都需要内存并且并非每个客户都需要连续访问一个固定的持久机制,所以在持久层
维护一个连接池,并且在所有客户当中共享连接是有必要的。
18 专用(native)和非专用驱动。数据库通常提供多种访问方式,一个好的持久层应该支持
这些常用的方式。连接方式包括使用ODBC、JDBC和由数据库厂商或者第三方提供的
专用驱动等。
19 语言绑定。你的软件需要能够访问你的持久层,因此持久层需要能够支持你所选择的开
发语言。
20 映射的灵活性。因为映射类层次结构有三种主要的方式(Ambler, 1998c),所以持久层
应该可以支持你所选择的不同映射方式。
21 生成数据库结构。如果你的CASE 工具不支持从对象结构产生数据库结构并且也不支
持从数据库结构产生对象结构,持久层就应该可以做到。尽管我已经指出(Ambler,
1998c)了这样做的问题,仍然有很多开发者选择了从对象/数据库结构自动生成数据库
/对象结构。
22 关系遍历。持久层应该支持在对象之间遍历关系,也包括自动的更新/创建/删除关系(包
括聚集关系)。
23 SQL查询。在面向对象的代码中写SQL查询是对封装原则的公然违背,这样会直接耦
合应用程序与数据库结构。然而,为了性能的原因,有时候需要这样做。在代码中的硬
编码SQL 应该是异常情况,而不是正常情况,并且在发生这样的异常前,应该仔细权
衡。不管怎样,持久层还是需要支持这种情况。
24 调用存储过程。尽管本文描述了如何避免使用难于移植的存储过程的方法,但是你会发
现在现实中偶尔还是要用到它。因此,持久层必须支持调用存储过程。
25 缓冲区。一个提高性能的方法就是缓冲对象。持久层应该实现一个对象缓冲区或者能够
访问一个外部的缓冲区。
26 锁。应该可以在访问数据的时候指定使用悲观的锁或者乐观的锁。这些锁类型将在本文
的后面详细讨论。
27 支持管理工具。多数持久层,至少鲁棒的持久层,是运行在元数据上的。元数据需要被
维护,理想状态下,用一个管理应用程序维护。
28 运行时刻配置。应该可以在运行时刻修改持久方法的某些特性,例如游标大小,持久机
制的名字/位置等。
持久层应该让应用程序开发者集中精力于他们所擅长的—开发应用程序,而不用关心他
们的对象是如何存储的。进一步说,持久层应该也允许数据库管理员(DBA)做他们最擅
长的—管理数据库,而不用担心在现有的应用程序中引入bug。对于一个好的持久层,DBA
应该可以移动表,重命名表,重命名列以及重新组织表而不影响应用程序对他们的访问。不
可能?打赌吗,我的经验是构造满足这些需求的持久层是完全可能的,实际上,设计就在下
面。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics