IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Web development | Information Management  >

优化 Project Zero 应用程序的数据库配置和依赖项

有关如何管理 Web 2.0 组件的数据库需求的实际建议

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 中级

Dan Jemiolo (danjemiolo@us.ibm.com), 顾问软件工程师, IBM 

2007 年 9 月 24 日

Project Zero 开发平台包括一个易用的数据访问库以让开发人员能够从其应用程序代码进行极少的配置即可执行 SQL 语句。实际上,设置数据库并连接到此数据库所需的只是一个四行的配置文件和一些基本的 SQL 知识,这二者都不会给 Web 开发人员增加太多负担。但即便数据库驱动的开发如此简单,围绕数据库驱动组件的包装还是存在很多问题,这些问题需要大量的关注:没有合适的设计,Zero 组件就有可能会拖累依赖项,而且会做出其他开发人员无法接受的假设。本文讨论了配置和包装数据库驱动组件的最佳实践,以使这些组件可以为其他 Zero 开发人员所用。

开始之前

本文假设您已经下载了 Project Zero 并且或者完成了 “用 Project Zero 开发应用程序” 入门教程或者自己编写过简单的应用程序。您应该对 Zero 数据访问库(称为 zero.data)和 Apache Ant 十分熟悉。您也应该使用如下数据库产品进行开发:

更多信息,请参阅 参考资料

简介

Project Zero 社区
请查阅 Project Zero 网站 以了解 Project Zero 是如何为如今的 Web 应用程序提供了功能强大但却极为简单的开发和执行平台的。

当包装 Zero 组件以便在产品系统中使用时,数据库配置就显得至关重要。没有合适的设计,Zero 组件就有可能会拖累依赖项,而且会做出其他开发人员无法接受的假设。如果 Zero 组件在不提取其内容和处理配置文件和脚本的情况下无法使用,那么它就不会被广泛重用。即便假设软件许可允许这么做,也很少有开发人员愿意担负起更改第三方代码的责任。本文如下的章节着重介绍了 Zero 组件的三个方面:配置文件、库依赖项和表创建,对 Zero 组件可进行优化以让它对数据库不可知、对用户友好。

优化配置文件

需要在 Zero 配置文件中指定组件的数据库连接的细节,包括驱动程序名称、数据库位置和身份验证信息。这可以在应用程序目录 /config/zero.config 下找到。清单 1 显示了一个可用于 blog 组件的示例 zero.config 文件,该组件使用了 Apache Derby 数据库:


清单 1. 带数据库配置的示例 zero.config 文件
                
[/app/db/blog/config]
class=org.apache.derby.jdbc.ClientDataSource
serverName=localhost
portNumber=1527
databaseName=BlogDB

这类组件的实现代码通过调用 zero.data 的 Manager.create() 方法并将数据库配置的名称传递给它(例如 Manager.create("blog"))来访问数据库。

清单 1 中代码对于初始开发和测试而言很好,但现在的情况是我们已经将数据库名称和数据库产品硬编码了我们的实现当中。如果有人想要在应用程序中重用我们的组件,他/她就必须要创建新的数据库实例(“blog”),而不能重用现有的数据库。如果他/她还没有使用我们的数据库产品,那么他/她就必须要安装和部署此数据库产品。在大多数产品环境中,这两个需求都非入门者所能处理得了的。部署人员也不可能为每个 Zero 组件都提供其自身的数据库,他们也不能为了一个组件而安装和维护额外的产品。简言之,配置必须要充分灵活以便能够适应用户的数据库环境,否则您的代码将得不到使用。在本节,我们修改了 zero.config 文件以使其能更好地适应新的环境。

删除硬编码的数据库名称

通向灵活性的第一个也是最容易的步骤是从面向数据库的代码中删除硬编码的数据库名称。清单 2 所示的代码设置了 blog 组件的 dbKey 属性值,该值可以在运行时利用 Zero 的 GlobalContext API 读取:


清单 2. 配置数据库名称
                
[/app/blog]
dbKey=blog

有了这个属性之后,我们就可以更改代码以使用 Manager.create(app.blog.dbKey) 而非 Manager.create("blog")。具体化数据库名称会让用户更容易对之进行更改,而无需在整个代码中搜寻。

但我们还可以做得更好。dbKey 属性的值既可以是数据库的名称,也可以是 defaultDB,后者是个特殊的值,它告知 zero.data 库去使用应用程序的数据库配置。而这正是我们所希望的!如果其他 Zero 开发人员将 blog 组件添加到其应用程序,他们可以在其应用程序的 zero.config 文件中重写我们的 dbKey 值,只需将该值设成 defaultDB 即可,如清单 3 所示:


清单 3. 重写数据库名称
                
[/app/blog]
dbKey=defaultDB
            

现在我们获得了一个很好的平衡:在开发和测试期间,组件使用 blog 数据库;在部署期间,我们的用户可以在其自己的 zero.config 文件中重写此名称以便它们可以匹配其数据库设置。

动态数据库配置

我们的数据库名称现在是动态的,不过 blog 组件在其 zero.config 文件中有专门特定于我们数据库设置的信息。清单 1 包含了特定于 Apache Derby 的一些设置,但即便如此,我们的 blog 组件仍可以很好地工作于 IBM DB2 或 MySQL,那么我们为何还要限制自己呢?

让配置动态化的第一个步骤是将配置从我们的 zero.config 文件中拉出。我们可以将 清单 1 中的文本放入另一个名为 data.config 的文件并将该文件包括到原始的 zero.config 文件,所使用的语法如清单 4 所示:


清单 4. 提取数据库配置
                
[@include data.config]

对于那些更小的、永远都不会作为单独应用程序使用的组件,我们完全可以到此为止。在将此组件包装以便重复分发之前,我们所需做的只是注释掉 @include 行,但前提是用户应用程序会提供我们所需的数据库配置。大功告成!

然而,还有很多的组件类型都是复杂应用程序的有用构建块,而同时又可以用作更复杂的应用程序本身。我们的 blog 组件就是这样一个很好的例子。有许多网站只有博客功能(例如 blogger.com)。而另一些网站,博客功能只是其用户体验的一部分(例如 MySpace)。如果用户希望将这类组件用作独立的应用程序,那么这类组件就必须具有动态设置数据库配置的能力。最理想的情况是此组件可以作为其安装过程的一部分来配置其数据库需求,而安装过程是用户通过使用 Zero 命令行界面发起的。

由于我们的数据库信息存在于单独的文件中,所以添加动态数据库配置非常容易实现。每个 Zero 组件都有一个 Apache Ant 文件(build.xml),可用来调用 Zero 命令行界面,可使用它来添加动态构建和部署逻辑。我们下一步要做的是添加 Ant 目标,这些目标可以针对用户数据库生成合适的 data.config 文件。您可以将清单 5 所示的 Ant 目标添加到 blog 组件的 build.xml 文件:


清单 5. 用来生成 data.config 文件的 Ant 任务
                
<property name="config-file" value="config/data.config"/>
    
<target name="create-derby">
  <echo file="${config-file}">
  [/app/db/blog/config]
  class=org.apache.derby.jdbc.ClientDataSource
  serverName=localhost
  portNumber=1527
  databaseName=BlogDB
  </echo>
</target>
	
<target name="create-mysql">
  <echo file="${config-file}">
  [/app/db/blog/config]
  class=com.mysql.jdbc.jdbc2.optional.MysqlDataSource
  serverName=localhost
  portNumber=3306
  databaseName=BlogDB
  </echo>
</target>
	
<target name="create-db2">
  <echo file="${config-file}">
  [/app/db/blog/config]
  class=com.ibm.db2.jcc.DB2DataSource
  serverName=localhost
  portNumber=50000
  databaseName=BlogDB
  </echo>
</target>
      

清单 5 为我们想要提供支持的三个数据库中的每一个都添加了一个目标。而每个目标都会创建一个具有特定于供应商设置的 data.config 文件。已经下载了我们的 blog 组件的用户若想将该组件作为单独的、受 Apache Derby 支持的应用程序加以运行,就需要发出清单 6 所示的命令:


清单 6. 运行 Ant 任务以创建面向 Apache Derby 的 data.config
                
$ zero resolve
$ zero create-derby
$ zero run

DB2 和 MySQL 用户则会针对其各自的目标替代 create-derby

至此,我们已经尽可能灵活地完成了我们的数据库配置来满足我们潜在用户的需求。接下来让我们来看看不必要的依赖项所存在的问题。

优化依赖项列表

要构建和测试数据库驱动的代码,就需要向可提供必要的 JDBC 驱动程序的组件中添加库。比如,如果所支持的是 Apache Derby 数据库,就需要使用 derbyclient.jar 文件,此文件在每个 Derby 发布中都会包括(在本节中,我们将继续使用 Derby 作为我们的示例数据库,但给出的建议也同样适合于其他的数据库产品)。包含 JDBC 驱动程序的 JAR 文件可以放置于组件的 /lib 目录,也可以使用 Apache Ivy 在构建过程中加以发现。在前一种情况,安装十分简单:将 JAR 文件复制到合适的目录即可;在第二种情况下,则需要向位于 /config/ivy.xml 的组件的 Ivy 文件添加一个条目。清单 7 给出了这样的一个条目:


清单 7. 面向 Apache Derby 的 JDBC 驱动程序的 Ivy 条目
                
<dependency name="derbyclient" org="org.apache.derby" rev="10.2+"/>
      

不管何种情况,都会向组件添加一个依赖项,而这会影响到用户。MySQL 用户将不会想让 Derby 驱动程序包括到其应用程序中,而反之亦然。未使用的依赖项可能不会对应用程序的准确性有任何影响,但它们的确会影响应用程序的大小和许可。任何人可能都不想使自己的组件看起来十分 “臃肿”,亦不想让其由于法律方面的原因而被禁止。为了避免这些问题,就需要将开发人员的需求和用户的需要分离开来。

将细节留给开发人员

当我们刚刚开始修改 zero.config 文件时,我们的目的是将尽量多的配置留给用户以不使自己陷入困境。我们在处理依赖项管理时仍然采用相同的办法:将必要的 JDBC 驱动程序包括到构建和测试环境中,但不让其出现在最终的发布中。

实现这个目标最简单的方法是添加必要的 JDBC 驱动程序,做法是使用 /lib 目录,然后再在创建发布工件的时候将其排除。Zero 命令行界面有一个 package 目标,它会取出组件目录中的所有内容并将其添加到一个 ZIP 文件;有一点您可能不太知道的是 package 目标具有可选的 excludes 属性,可用来排除某些文件和目录。清单 8 中的 Ant 目标将 excludes 设置成我们想要排除的 JAR 文件的列表,然后调用 Zero 的 package 目标:


清单 8. 从组件包中去除驱动程序
                
<target name="clean-package">
  <property name="excludes" value="lib/derbyclient.jar"/>
  <package/>
</target>
      

可以将此 Ant 目标添加到组件的 build.xml 文件,如同我们处理 清单 5 中的目标一样。当我们准备好创建发布文件后,只需运行 zero clean-package,而非通常的 zero package。我们现在就具备了数据库驱动组件,该组件就其配置而言十分灵活且没有任何不需要的文件。

优化特定于供应商的表创建

不幸的是,并不是所有项目都会如此规整,也不会像我们在之前的两个章节中描述的那样简洁。有时,不管如何试图避免,逻辑或配置仍必须 要特定于供应商。有关如何编写独立于供应商的 SQL 语句的文章很多,在这里无需重复。相反,我们将重点分析一种无法避免特定于供应商的 SQL 的情况:创建数据库表。在这种情况下, 所具备的 SQL 脚本是您在安装过程中想要运行的,但您并不能提前知道用户将会使用哪个数据库。所幸的是,相应的解决方案并不遥不可及。

Ant 来帮忙(再次!)

清单 5 中,我们创建了特定于供应商的 Ant 任务,这些任务都可以在安装时生成特定于供应商的配置文件。我们现在将要对这些任务进行添加,通过执行特定于供应商的 SQL 来创建数据库表。让我们假设我们已经组织好了以数据库产品命名的目录中的所有 SQL 脚本(比如,/sql/derby 和 /sql/mysql)。我们的目标可以利用这一约定通过 Ant 的 sql 任务寻找和执行正确的 SQL 脚本。清单 9 给出了 create-derby 目标是如何被修改以设置特定于 Derby 的属性的,sql 任务会使用这些属性执行正确的脚本:


清单 9. 扩展 Ant 任务以执行 SQL 脚本
                
<property name="config-file" value="config/data.config"/>
    
<target name="create-derby" depends="init-derby, create-tables">
  <echo file="${config-file}">
  [/app/db/blog/config]
  class=org.apache.derby.jdbc.ClientDataSource
  serverName=localhost
  portNumber=1527
  databaseName=BlogDB
  </echo>
</target>
	
<target name="init-derby">
  <property name="db-name" value="derby"/>	
  <property name="db-driver" value="org.apache.derby.jdbc.ClientDriver"/>
  <property name="db-jar" value="lib/derbyclient.jar"/>
  <property name="db-url" value="jdbc:derby://localhost:1527/db/BlogDB"/>
</target>
	
<target name="create-tables">
  <sql driver="${db-driver}" 
    classpath="${db-jar}" 
    url="${db-url}" 
    src="sql/${db-name}/create-blog-tables.sql"/>
</target>
    
      

现在,当部署者运行 zero create-derby 时,除了生成 zero.config 文件之外,它还会创建合适的数据库表。我们的 MySQL 和 DB2 目标都可以用相同的方式进行扩展,即通过添加同等的 init- 目标。用户现在就可以确保组件的数据库是通过使用对应于其产品的正确语法创建的。惟一的一个缺陷是我们必须为所有的供应商都要发布 SQL 脚本。由于这类脚本通常都是相对较小的文本文件,而且没有许可方面的隐患,因此无需过分担心。

结束语

分享本篇文章……

digg 提交到 Digg
del.icio.us 发布到 del.icio.us
Slashdot 提交到 Slashdot!

若要包装 Zero 组件以供其他开发人员重用,需要考虑的事情很多,而其中大多数问题都是由数据库访问引起的。在本文中,您了解了如何减轻开发人员在进行开发时不知不觉为用户制造的一些限制和问题。借助 Apache Ant 和 Zero 命令行工具,就能消除与发布数据库驱动组件相关的大多数常见问题。



参考资料

学习

获得产品和技术

讨论
  • Project Zero 社区 站点包含了参加论坛讨论、blog 和 wiki 的邀请。今天就加入吧!



关于作者

Dan Jemiolo 是 IBM 位于美国北卡罗来纳州 Research Triangle Park 的 Autonomic Computing 团队中的一名顾问软件工程师。他负责 Apache Muse 2.0 的设计和开发而且现在还在为此项目工作。Dan 还参与过 WS-RF TC,担任 WS-ResourceMetadataDescriptor 规范的编辑,他亦参与制订过 IBM 在更多地采用 Web 服务标准方面的策略。从 Rensselaer Polytechnic Institute 获得了理学硕士学位之后,他加入 IBM 刚刚两年。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?




回页首


IBM 和 DB2 是 IBM Corporation 在美国和/或其他国家的商标。 其他公司、产品或服务的名称可能是其他公司的商标或服务标志。

IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款