IBM ORDBMS 数据库提供了大量功能,可以简化软件开发,减少硬件需求,以及加快进入市场的步伐。您必须在设计中善加利用,以便从中受益。IBM ORDBMS 不仅仅是一个持久性存储器,更是一条提高您生产率和效率的路径。
非同小可的对象危机
理论上,以及在许多实际案例中,对于持久对象的操作需要实例化该对象,对其进行操作,以及与持久性存储器保持同步。这就导致了容器治理的持久性以及独立于数据库的思想:“使用容器治理的持久性的好处是,实体 bean 可以在逻辑上独立于存储该实体的数据源。…”
该规范还提到数据源可以是关系型的,也可以是非关系型的,如 IMS。当然还可以是面向对象的数据库。任何修改容器治理 bean 的交互都需要与该数据源保持同步,以确保实体 bean 的一致视图。对 EnterPRise javaBean(EJB)使用 chatty 接口会显著地增加数据库的交互量,从而可能导致性能问题。
“每次实例化一个对象”的中心思想有可能会引起性能和容量问题。该问题不是仅限于容器治理的实体 bean 的使用中,而是普遍存在于面向对象方法中。让我们用一个简单的示例来加以说明。 假设有一家专门从事贷款发放的大型银行。它遍及多个区域,每个区域包括几十甚至上百家支行。
图 5. 银行贷款机构
图 5 说明该银行对应多个区域,每个区域都有多个支行,而每个支行又进行多项贷款。它还显示我们可以获得不同种类的贷款。
假如该银行需要获得一份清单,列出那些在贷款中承担了过高风险的支行,它就会按区域来收集该清单。每个区域将搜索其支行,找到那些风险过高的。而支行本身必须查询每一项贷款的风险和贷款额,用以计算该支行的平均风险。
以下是一种适宜的对象方式:每个对象封装自身的信息和处理。支行要获得贷款风险的惟一方法就是向该贷款查询这一信息。该方式比较合理,因为它消除了对象类型之间的紧密耦合。对象间的通信取决于定义良好的接口。只要该接口保持不变,就可以修改其实现,且不影响整个系统。
本例中,假如我们考虑:该银行遍及 10 个区域,每个区域有 100 家支行,而每家支行又有 10,000 份贷款,我们总共创建了 1000 万多个对象来响应该查询。要求每份贷款返回两个值:风险级别和贷款额。在区域和支行之间的通信中,这会在两个对象之间传递超过 2000 万条消息。最后从内存中删除这些对象需要进行额外处理。
所使用的数目(10/100/10,000)丝毫不过分,我们绝对可以想像将生成更大数量级对象的系统。这很轻易成为一个性能以及容量(例如内存)问题。若通过给应用程序服务器增加节点来解决该问题,非但解决不了,反而会增加复杂性。
通过利用 DB2 和 IDS 等对象-关系数据库的优点,即使无法消除该问题,也可以有所缓解。请记住,大多数面向对象人员仅仅将数据库看作持久性存储器。他们习惯于将所有处理放在对象的代码中完成,事后才添加数据库。
假如考虑面向对象是何时成为主流的,我们就可以设想,现在绝大多数 30 出头或更年轻的程序员已经被练习成以这种方式来思考了。由于数据库仅仅用于“持久保存”对象以及检索它,所以系统开销最小的数据库在该模型中就占有优势。这会有利于层次、网络和对象数据库。而对象-关系型的数据库可以完成比持久保存对象多得多的功能,却成为永远不被启动的大引擎。这就好比是在一场用赛车对抗自行车的比赛中,却不答应您发动引擎一样。
让我们来解释一下:面向对象方法是优秀的。问题在于许多架构师和开发人员视野过于狭隘,不知道可以选择将处理置于何处。这一选择结果会影响设计,并且可以带来重大性能影响。利用 ORDBMS 的优点可以简化设计,以及极大地提高结果系统的性能。这相当于加快进入市场的步伐,以及降低开发和维护的成本。更快的结果还可以带来重要的商业优势。
数据库独立性
我在前面已提到 J2EE 通过促进数据库独立性来提高应用程序的可移植性。并且还进一步提到可以是任何类型的数据库:关系(对象-关系)或非关系的。这是整个 J2EE 体系结构的一个美好目标,但在构建商业应用程序中却是一种十分危险的方法。
商业应用程序的目标应该是提供对抗竞争者的商业优势,而非可移植性。可移植性是一个次要目标。假如需要进行移植,可以将不可移植的部分隔离起来,以便限制所需的工作。我们需要以尽可能最低的成本获得尽可能快的响应。假如您针对移植性进行设计,就要设计最底层的功能,从而放弃所有优势。这就像雇主拒绝雇用一个高度称职的人,因为怕他某一天离开,而下一任雇员的能力可能远远不及。按照该逻辑,我们应该雇用最无能的人。否则的话,我们应该确保限制雇员对公司的贡献,这样,假如我们哪天必须用一个逊色一些的人来接替他时,就不会感到失望。期望越多,您将得到越多。而期望越少,您得到的也会随着时间越来越少。
这同样也适用于企业应用程序。您应该权衡您的数据库系统的所有功能,并且对于能够带来商业优势的功能善加利用。您可以在设计中隔离数据库的交互,以便当您偶然必须迁移到另一数据库时,就只需要完成有限的移植工作。由于数据库的竞争十分激烈,所以,很可能您现在计划使用的独特的新功能将来会出现在某个竞争对手的数据库中。或者,在数据库供给商为争取您的业务,协商将如何补偿其缺点时,这可能成为其中的一个缺点。因此,设计要谨慎,但也要赢得成功。
J2EE 复杂性
J2EE 具有许多好处,有助于商业应用程序的开发。它们包括平台独立性、组件架构、多层应用程序模型、统一的安全模式以及一个丰富的标准集合,这些标准涉及事务控制、数据库访问和消息传递等领域。实际上,J2EE 在一个架构下集成了过去 50 年左右软件中所取得的进展。这也付出了一定的代价:复杂性。
尽管 WebSphere Studio application Developer 等工具明显地简化了开发,而且 WebSphere Studio Application Developer 治理控制台提供了控制,在启动大型项目之前,我们还是必须确保已经具备了适当的专业知识。最有效的方法就是培训与聘请专家顾问相结合。
同样重要的是,要具有一支包括了各个领域专家的综合队伍。在项目启动之前,要将这支队伍聚集在一起。例如,数据库治理员(DBA)和 SQL 专家应该从一开始就一起讨论将如何使用不同的对象。让我们用一个示例来加以说明。
从 DICOM 对象之间的关系。我们看到,每一种类型的 DICOMData 都可以包含许多其他的 DICOMData 对象。我们可以通过标准的关系方法或使用新的数据类型,在数据库中表示该层次结构关系。一个数据元素是由一个标签(tag)和一个值表示。存在不同类型的值,如字符串、日期(date)、小数(decimal)等一个值还可以具有重复字段。一个 DICOMData 对象有可能包含几百种不同的数据元素。但实际上,数目要少得多。
将一个 DICOMData 对象表示为一大行几乎为空的数据元素既不实际,也不可能。那么,我们可以将 DICOMData 对象表示为 DICOM 对象本身与数据元素之间的关系。第一种方法是为每一种类型的数据元素预备一个数据元素表。这会产生 23 个表,而且检索一个 DICOMData 对象要连接 24 个表。其他的方法可能答应我们将 23 个表缩减为一个。即便如此,通过关系型数据库来存储和检索 DICOMData 对象也要付出昂贵的代价。
假如数据库专家恰好从一开始就参与进来了,那么就可以讨论这些问题,并可以揭示那些使实现更加轻易的新信息。结果显示每种类型的 DICOMData 对象中只有少数元素将用于搜索。这就答应我们表示 DICOMData 对象中的少量值,并且将所有其他的数据元素组合成一个大型对象列。在存储和检索 DICOMData 对象时,这带来了显著的性能提高。
在前一小节中,我们讨论了通过向每个支行查询贷款上所承担的平均风险度导致的对象爆炸(见图 5)。DB2 UDB 和 IDS 的对象-关系功能答应我们扩展数据库功能,以便在数据库中包含风险计算函数。那么,我们可以使用存储过程或用户定义的聚集来计算每个支行的平均风险。我们甚至可以添加条件,其中定义了不能接受的风险级别,并且规定只检索处于过高风险中的支行清单。结果带来了显著的性能增长,因为我们不必实例化一百万个对象,并且避免了对象之间的多数消息传递。在对象人员看到了许多对象创建和通信的地方,数据库人员可以找到直接提供对策的办法。在恰当的地方进行处理将提供更简单、更高效的解决方案。
J2EE 的其他方面也增加了它的复杂性。这包括牵涉共享 EJB 的多线程环境。您如何共享 EJB 呢?在一次更新中又如何协调多个 EJB 呢?您的代码是可重入的,还是设置必须锁定的临界区呢?这将导致许多问题,如数据完整性、锁定策略以及数据库人员所熟知的一些问题。
那么,存在 EJB 访问的性能问题,您需要以怎样的粒度进行才能获得高性能。您还必须确定如何监控应用程序以找到性能瓶颈。
J2EE 环境在开发和运行企业应用程序中表现极佳。但由于其复杂性,不宜滥用。假如希望项目取得成功,您就要在初期组织好一支合适的专家队伍来共同完成。
寻求解决方案本文前面所提出的问题没有理想的解决方案。要从正确的培训抓起,这样您才能充分使用解决方案的所有组件。其中可能包括在 Web 浏览器中使用 applet、中间件当中的合理设计、以及利用数据库系统的优点。
图 6. 对象集合
上面的示例说明应该仔细检查一个对象里对象集合的使用。我们必