内容:
相关内容:
Advanced database operations with JDBC
哪种 J2EE 技术最适合您的企业?
级别:中级
Kyle Gabhart(kyle@gabhart.com)
顾问,Gabhart Consulting
2003 年 6 月
J2EE 平台为管理企业数据持久性提供了一组丰富的选项,但如何选择适合于您体系结构的选项呢?Kyle Gabhart 介绍了 J2EE 最佳的数据持久性技术 — 实体 bean、JDBC 和 JDO — 并在几个不同环境中比较它们。
数据持久性是企业开发中最棘手的一个方面。一个企业数据持久性解决方案必须提供迅速的客户机事务,随着时间的过去确保数据完整性,以及在如系统崩溃和网络故障之类的日常灾祸发生时使数据继续存在。在 J2EE 探险者系列接下来的两个部分中,我们将着重讨论 J2EE 技术,这些技术有助于您为企业体系结构创建可靠的数据持久性解决方案。我们将通过简要地介绍企业应用程序中的数据持久性来开始该主题,然后继续更详细地讨论各种技术选项。在本部分中,我们将比较实体 bean 的一站式(single-stop)解决方案同更复杂的(但更健壮的)会话 bean 与 Java 数据库连接(Java Database Connectivity,JDBC)代码的组合。在下一部分中,我们将比较 Java 数据对象(Java Data Object,JDO)与实体 bean。
什么是数据持久性?
数据是任何计算机应用程序最重要的方面。计算机应用程序的核心是使某人或另一个计算机系统能够访问其数据。在企业环境中,数据不仅必须是可访问的(即,与用户界面连接并按一系列业务规则管理),而且还必须是持久的。持久数据存储就是即使在服务器崩溃的情况下仍能存在的数据存储。
持久数据存在于应用程序的活动内存之外,通常在数据库或平面文件系统中。虽然持久数据被读入瞬时存储器以供使用或修改,但它始终被写到外部数据存储中以长期存储。美国国家标准与技术研究所(The United States National Institute of Standards and Technology)(请参阅参考资料)定义了三种级别的持久数据:
部分持久数据是一种仅允许对最新版本更新的持久数据结构。
持久数据是一种保留其旧版本的数据结构;即,以前版本和当前版本都可能被查询。
完全持久数据是一种维护其数据的所有版本并允许对这些版本更新的持久数据结构。
大多数业务应用程序至少提供部分持久数据。这种类型的持久性在事务中期或者甚至在请求中期出现系统故障时容易遭破坏,这会导致数据不完整且常常遭毁坏。另一方面,在持久数据实现中,对系统中断或故障以“回滚(rollback)”回应,数据状态被回滚到上一个已知的良好配置。持久数据实现在企业体系结构和数据库管理系统(DBMS)中很常见。完全持久数据实现非常少见。完全持久数据实现的少数几个示例有:日志记录文件系统、VMS 文件系统(如 VAX 和 Mac OS X)以及并发版本控制系统(CVS)。
J2EE 中的持久性
信息时代非常强调分布式企业计算平台的使用。在这类平台上,必须不惜任何代价保护数据并使其永远持续存在,即使面临网络故障、内存泄漏和服务器崩溃时,也是如此。为了维护这种持久性,应用程序组件必须能够处理并发性、连接管理、数据完整性和同步。J2EE 的所有三种数据管理技术都为开发人员处理这些功能,但每种技术在处理时略有不同。
实体 bean,它提供健壮的数据持久性。bean 容器处理大部分的数据完整性、资源管理和并发性功能,从而使开发人员关注业务逻辑和数据处理,而不是这些低级细节。使用 bean 管理的持久性(Bean Managed Persistence,BMP)实体 bean 时,开发人员编写持久性代码而容器确定何时执行该代码。使用容器管理的持久性(Container Managed Persistence,CMP)实体 bean 时,容器生成持久性代码并管理持久性逻辑。
JDBC,当与会话 bean 结合时,它可提供简便的 EJB 开发和与平台无关的部署,而没有象 EJB 技术那样的资源使用和内存开销。象 BMP 实体 bean 一样,该解决方案要求开发人员编写持久性代码。与 BMP bean 不同的是,它还要求开发人员编写持久性逻辑。因而,开发人员负责确定何时将数据持久保留在数据存储中以及何时从数据存储装入数据。
Java 数据对象是最新的持久性机制。JDO 提供了面向对象的持久数据存储。开发人员使用 POJO(无格式普通 Java 对象,plain ordinary Java object)来装入和存储持久数据。
我们将在余下的文章中讨论实体 bean vs. 会话 bean 和 JDBC 组合的优缺点。
实体 bean 的优点
谈到企业级数据持久性时,实体 bean 有下列优点:
标准化。EJB 规范定义一组与供应商无关的接口,J2EE 供应商可以实现这些接口来支持实体 bean。这种标准化允许采用最佳实践的开发并缩短雇用新开发人员时的适应期。因为基本的组件体系结构和设计模式大家都知道,所以很容易找到合格的人才来实现它们。
容器管理的服务。正如我们在本系列的前两篇文章中讨论的那样,EJB 容器管理的服务为处理诸如安全性、事务处理、连接合用和资源管理之类的企业功能提供了极大的好处。
透明持久性。容器管理的服务思想在 CMP 实体 bean 中得到了进一步加强。这里,容器还自动管理持久性语义。使用 BMP 实体 bean 时,开发人员必须编写持久性逻辑,而容器则确定何时调用由开发人员定义的方法。同时使用 CMP 和 BMP 实体 bean 时,容器决定何时持续保持 bean 的状态以及如何确保与底层数据存储的数据完整性和并发性。
事务支持。开发人员对 CMP 事务(隔离级别、事务需求和方法的包含/排除)有粗粒度的控制权,对 BMP 事务有细粒度的控制权,这些控制都是通过在 bean 代码中以程序方式处理事务语义实现的。在这两种情况下,容器管理事务并确定是否应该提交给定的事务。
基于组件的设计。实体 bean 被设计成自包含组件,这些组件配置有部署描述符,无需更改任何代码就可以将它们部署到任何 J2EE 应用程序服务器。
实体 bean 的起落
然而,当架构设计师、开发人员和顾问开始使用实体 bean 时,它的吸引力和魔力就开始迅速消失。在 EJB 1.1 规范得到广泛实现时,事实表明使用实体 bean 必须小心谨慎。虽然它们仍代表了数据持久性的功能强大的组件-模型体系结构,但它们消耗过多的服务器资源这一点也是众人皆知。EJB 2.0 规范已经缓解了其中一些问题。虽然许多人仍需要从使用 EJB 1.1 实体 bean 的影响中恢复过来,但是与往日相比,实体 bean 现在变得更可信赖,是一种更可行的解决方案。随着本地接口出现、CMP 能力得到增加、J2EE 供应商具备更多有关实现 EJB 规范的经验,实体 bean 在整个业界再次成为可行的数据持久性机制。
1999 年,当首次引入 J2EE 和 EJB 规范时,实体 bean 被吹捧为是一种卓越的企业组件,它会彻底改变企业应用程序的开发、维护和可移植性。令业界振奋的是实体 bean 代表了一种没有麻烦的、自动持久性机制。
总之,实体 bean 从标准化和业界最佳实践中受益,简化了企业开发的某些复杂性并提供引人注目的基于组件的设计。
实体 bean 的缺点
虽然实体 bean 确实有一个令人印象深刻的特性列表,这为它们添色不少,但我们还是要考虑它们的缺点,其缺点如下:
设计复杂。容器管理的服务和自动透明持久性的代价很高。它们在几个级别上给应用程序设计带来复杂性。首先,为了避免网络开销并强制遵守业务规则,几乎总是通过会话 bean 访问实体 bean。因此,每个事务至少涉及两个企业 bean(往往会多得多)。涉及的组件越多,则体系结构的设计、编码和维护就变得越复杂。其次,存在自动操作成本。容器有点类似于有魔力的黑盒。只要它认为适当,就会调用 bean 回调方法,它可随时选择创建和破坏 bean 实例,激活和钝化 bean,并且将其状态存储到持久数据存储中或从其中装入。应用程序代码无法控制这些事情发生的方式或时间。从积极的方面看,容器的功能减少了编写业务逻辑时要考虑的问题数量。从消极的方面看,容器对装入条件和数据请求模式的响应是不可预知的,所以必须在开发过程中添加大量的基于方案的装入测试。
较长的构建周期。由于企业 bean 和(尤其是)实体 bean 的复杂性,所以一次迭代(设计/构建/测试/集成/测试/部署)所花的时间比可比较的 Java 持久性解决方案所花的时间长两到三倍。
响应时间。根据服务器上的负载和所请求实体 bean 的相对大小,实体 bean 的查询可能有不达标的响应时间。实体 bean 在本质上受限于 bean 实例的粒度。要么必须装入整个 bean,要么根本无法装入 bean。该粒度会促使体系结构变得更复杂,因为唯一的选择就是用较差的响应时间使 bean 保持原样,还是将数据分成更小的实体,从而使系统体系结构变得更复杂。
资源使用情况。所有企业 bean 都是资源霸占者。实体 bean 大概是最大的霸占者。虽然这将视使用的应用程序设计模式以及供应商如何有效地设计其实体 bean 实现而变化,但实体 bean 仍倾向于消耗大量的服务器资源。
总之,实体 bean 的缺点是复杂性和较长的构建周期,从而使设计和开发包含它们的系统变得更困难。在生产中,实体 bean 因霸占资源和对大实体的并发请求响应极慢而声名狼籍。
会话 bean 和 JDBC
无状态会话 bean 的受欢迎程度不象实体 bean 那样大起大落(请参阅侧栏)。事实上,在普及和功能方面,无状态会话 bean 自 1999 年(当年发行了 EJB 规范)开始就一直保持稳定和可靠。它们产生性能极佳的结果和有效的资源合用,并且是 EJB 系列的一个重要工作程序组件。无状态的会话 bean 的稳定性和可预知性使它们成为管理持久企业数据的优秀候选者。
无状态会话 bean 常常与 JDBC 相结合来创建可靠的持久数据管理解决方案。在下面两节中,我们将衡量该解决方案的优缺点,但我们将不探究这两种技术本身的细节。如果您需要学习有关无状态会话 bean 或 JDBC 的更多内容,请参阅参考资料。
它是如何工作的
因为会话 bean 没有一种固有的数据访问机制,所以它们必须使用资源管理器连接工厂。资源管理器是 J2EE 容器的一个组件,它管理特定类型资源的整个生命周期,包括连接合用、事务支持以及使实际连接变成可能的任何必需的网络协议。连接工厂是用于创建至资源管理器的连接的对象。EJB 规范定义了 JDBC、JMS、JavaMail 和 JCA 资源的资源管理器。
在基于会话 bean 和 JDBC 的持久性体系结构中,会话 bean 将所有访问命令都委托给 JDBC 层。在接收调用时,会话 bean 使用 JDBC 来获得实现 javax.sql.DataSource 接口的对象。然后,返回的对象充当 java.sql.Connection 对象(由 JDBC API 定义)的资源管理器工厂,这些 java.sql.Connection 对象实现与数据库管理系统的连接。一旦获得了 Connection 对象,其余的持久性代码和业务逻辑(查询、更新、存储过程调用、结果集浏览和事务提交/回滚等等)就是纯 JDBC。
会话 bean/JDBC 的优点
会话 bean 和 JDBC 成为处理企业数据持久性的极佳组合。该组合最受认可的优点如下:
设计简单。从体系结构设计观点来看,通过会话 bean 来直接处理数据管理比使用实体 bean 简单得多。
细粒度的控制。因为会话 bean 是通用的工作程序组件,所以它们允许开发人员完全控制整个持久性过程,包括高速缓存、持久性、并发性、同步及其它。相反,CMP 实体 bean 不允许开发人员控制持久性机制,而 BMP 实体 bean 仅使开发人员能够定义应发生什么,而不能定义应在何时或什么样的情况下发生。
成熟。JDBC 存在了七年左右!而实体 bean 出现至今只有三年多的时间。JDBC 的可靠性和最佳实践对于 J2EE 持久性机制的开发来说是一笔非常宝贵的资产。
速度。因为开发人员完全控制在会话 bean 中使用的数据访问机制,所以可以针对某些任务优化数据访问和持久性逻辑。由于直接和有目的的操作,这可以产生极快的响应时间。
总之,会话 bean 和 JDBC 的组合能使开发人员对数据管理语义有细粒度的控制权,这一组合利用健壮且成熟的数据管理技术,支持功能优化,并将它全部封装成一个相对简单的组件体系结构中。
会话 bean/JDBC 的缺点
到目前为止都在谈论会话 bean 和 JDBC 组合的优点,但它也有一些缺点。缺点如下:
实现复杂。虽然这种系统的体系结构设计相当简单,但实际的会话 bean 实现常常十分复杂。如果应用程序的数据需求相当复杂,那么可能就无法实现管理数据库连接、确保数据完整性以及正确处理事务语义这些关键任务。开发人员常常需要实现某种类型的高速缓存同时确保最优性能。构造这种高速缓存机制使该系统的开发和维护进一步复杂化。
非固有的事务性。实体 bean 本质上是事务性组件,这些组件具有可配置的事务语义;而会话 bean 没有。将事务语义直接编码到应用程序代码中时,开发人员必须处处小心以确保每个功能的业务规则、流控制和事务完整性都得以保护并且可以容错。在实体 bean 开发中,这些细节都由容器处理。
持久性不是自动的或者得不到保证。在实体 bean 操作中,容器处理 bean 状态的持久性,并确保这种数据得到保护,供以后使用。对于会话 bean,将数据保持在安全、长期的数据存储中是开发人员的责任。
总之,与 JDBC 结合的会话 bean 遭受三个关键问题:bean 的实现常常是复杂的;会话 bean 没有固有的事务性;持久性机制不是自动的或者得不到保证。
进行调用
尽管还有不足,J2EE 架构设计师已开始宣布带有原始 JDBC 调用的纯无状态会话 bean 是最安全和最受推崇的数据持久性机制。这并非主要因为该组合是优于实体 bean 的解决方案(两者各有所长),实际是因为它有推动力。在实体 bean 很快脱颖而出又很快失宠的时候,对会话 bean 和 JDBC 的接受程度却随着时间的推移缓慢而稳定地积累起来。
不管当前趋势是什么,仔细地权衡实体 bean 和会话 bean 与 JDBC 组合的优点总是值得的。下面的列表标识了比较这两个数据持久性解决方案的四个关键方面:
读/写需要。需要经常读取且从不更改或偶尔更改的数据最好由会话 bean 与 JDBC 组合来处理。开发工作会简单直接,并产生极好的响应时间。
如果数据需要频繁更新并支持许多并发请求(因此有许多并发更改),那么实体 bean 是当然的选项。在面对数据的并发请求时,为确保数据完整性、同步和频繁的持久性而构建一种机制所涉及的复杂性简直太难克服了,而且不值得花时间和精力来创建它。
事务支持。CMP 实体 bean 使开发人员不必关心事务环境。所有事务细节都在 bean 的部署描述符中声明。如果可以接受这一级别的控制,那么 CMP 实体 bean 无疑提供了最容易的解决方案。如果需要更多的控制,那么 BMP bean 允许开发人员定义应该采取的操作,而不必为应该何时触发这类操作来编写业务规则。对于最大级别的控制,应该使用会话 bean。会话 bean 会管理涉及 CMP 和 BMP 实体 bean 的复杂事务,以及少数直接访问数据库的 JDBC 调用。
上市时间。CMP 实体 bean 显然是所有 J2EE 持久性机制中唯一一个上市时间最快的。声明数据类型和名称,定义部署设置,然后由应用程序服务器和供应商工具负责其余部分。很难讲 BMP 实体 bean 和会话 bean 与 JDBC 组合哪个能排上第二快的解决方案。一方面,BMP 会更快,因为容器正代表 bean 提供如此多的生命周期服务。而另一方面,会话 bean 会领先,因为它们没有 BMP 那么复杂,所以构建/测试/部署周期更短。最后,在这三种解决方案针对您的特定项目时给它们排序只是整个比较过程的一部分。还必须针对下一个类别(资源使用情况)来权衡这个评级。
资源使用情况。实体 bean 因消耗大量的资源(尤其对特别大的实体进行并发请求时)而声名狼籍。与之相比,会话 bean 和 JDBC 数据源连接是非常轻量级的,只需要少量的服务器资源。有关这一点的更多信息,请阅读本系列的第一篇文章“J2EE technologies for the stateless network”(请参阅参考资料中的 J2EE Pathfinder 系列文章)中概述的无状态会话 EJB 实例-合用模型描述。
结束语
在 J2EE 探险者系列的第三部分中,我们针对数据持久性将实体 bean 与会话 bean 和 JDBC 组合作了比较和对照。这里讨论的方案并未涵盖所有情形,但是它们代表了实体 EJB 组件和会话 EJB 组件的一些最常见用法。
下个月,我们将通过比较实体 bean 和 Java 数据对象(Java Data Object)来继续研究 J2EE 数据持久性机制。祝您到那时“探索”愉快!