用ant 进行derby数据库开发

来源:互联网 发布:dbscan聚类算法 java 编辑:程序博客网 时间:2024/04/20 08:30

用 Apache Ant 进行 Derby 数据库开发

developerWorks 文档选项 将此页作为电子邮件发送

将此页作为电子邮件发送


最新推荐

Java 应用开发源动力 - 下载免费软件,快速启动开发


级别: 初级

James M. Snell, 软件工程师, IBM

2005 年 1 月 01 日

开放源代码 Derby 数据库引擎为开发人员提供了一个用于轻量级数据库开发的强大工具。Derby 数据库基于文件系统,可以在不同平台之间移植。由于这个原因,通常的策略是在开发时创建数据库,并将数据库与二进制发布文件一起发布,而不是动态创建数据库。在这篇文章中,作者 James Snell 介绍了少量 Apache Ant 任务,这些任务使得将 Derby 数据库的构建和发布包含到应用程序的构建过程中变得更加容易。

Apache Ant 是每个开发人员在他们的开发工具箱中必备的几种工具之一。它的灵活性和可扩展性使之成为几乎可以为任何类型的应用程序创建健壮、灵活的应用程序构建过程的理想工具。

Apache Derby 是一种高质量的、纯 Java™ 的嵌入式关系数据库引擎,IBM® 最近已将其捐献给开放源码社区。Derby 数据库基于文件系统,具有高度的可移植性,并且是轻量级的,这使得它非常便于发布。

Snell 强调,为了使用 Derby 进行实验和开发,通过创建少量定制的、简单的 Ant 任务,将 Derby 数据库的创建和打包与应用程序二进制文件基于 Ant 的编译相集成,这样很有帮助。

入门

基本的 Ant 包发布时附带了很多类型的基本任务,其中有一项任务允许在 Java Database Connectivity (JDBC) 数据源上执行 SQL 语句。虽然这项任务能够很好地在 Derby 数据库引擎上工作,但是对于很多需要处理的关于 Derby 的独有特征,SQL 任务无法胜任。

Derby 是一种嵌入式数据库。对于每个 Java 虚拟机(JVM)实例,只允许加载一个 Derby 实例。每次只允许一个 Derby 实例访问任何给定的数据库。当 Derby 实例连接到一个数据库时,就会创建一个锁,以帮助强制实施这些规则。去掉这个锁的惟一方法是拆掉 Derby 到数据库的连接。仅仅关闭 JDBC 连接还不足以切断它们之间的连接。为了确保数据恢复检查点和其他各种数据库管理功能得到正确的处理,关闭 Derby 中的数据库也很重要。虽然 SQL Ant 任务完全可以启动 Derby 嵌入式数据库,并在该数据库上执行 SQL 语句,但它不能处理适当的 Derby 关闭任务,这些任务需要恰当地使用 Derby。

通过提供一些显式地控制 Derby 和各个数据库连接的负载状态的方法,这里介绍的 Ant 任务对上述问题作出了简单的回答。为使用这些任务,需要从 Apache Ant Web site(http://ant.apache.org)获得 Ant version 1.6.2 以及最新的二进制版本的 Derby 数据库引擎( http://incubator.apache.org/derby)。这些任务还将使用来自 IBM( http://www.ibm.com/developerworks/db2/zones/cloudscape/)的 Cloudscape 10.0 发行版。





回页首

构建过程

集成 Derby Ant 任务要创建的第一个关键步骤是识别被调用任务的基本顺序。对于 Derby,这些步骤是:

  1. 启动嵌入式 Derby 数据库引擎。
  2. 打开到您想要使用的 Derby 数据库的一个连接,指定是否创建数据库(Derby 可以根据需要创建一个新数据库,只要在数据库连接字符串中指定了一个特殊的 create=true 参数,Derby 可以通过打开到它的一个连接来创建新数据库)。
  3. 执行一系列的语句,这些语句可能创建/修改/填充表,创建/修改视图等等。
  4. 关闭和停止数据库连接。
  5. 关闭嵌入式数据库引擎。

此外,还有三种不同的 Ant 任务用于补充 SQL 任务中的构建(built)。

  1. StartDerbyTask.java:通过使用 ClassLoader 启动嵌入式数据库引擎,将它的 JDBC Driver 装入内存中。
  2. StopDatabaseTask.java:完全地、正确地关闭 Derby 到数据库的连接。
  3. StopDerbyTask.java:关闭嵌入式数据库引擎。这样将不允许再对 Derby 进行调用。

还有第四种任务,通过该任务可以访问 Derby 引擎附带的一个非常重要的实用程序:

  • DBLookTask.java:提供对 dblook 命令行实用程序的访问,该实用程序允许导出用于给定数据库的 DDL。该任务不能嵌套在 DatabaseConnectionTask 中并打开它自己的到数据库的连接。

在本文附带的下载资源中,有一个例子 Ant 构建脚本,该脚本一一使用了这些任务。清单 1 展示了这个例子脚本。


清单 1. 例子 Derby Ant 构建脚本
        <project name="demo" default="demo">  <!-- Define the Derby Ant Tasks -->  <taskdef     name="startDerby"     classname="com.ibm.developerworks.derby.ant.StartDerbyTask" />  <taskdef     name="stopDerby"     classname="com.ibm.developerworks.derby.ant.StopDerbyTask" />  <taskdef     name="stopDatabase"     classname="com.ibm.developerworks.derby.ant.StopDatabaseTask" />  <taskdef     name="ddlExport"     classname="com.ibm.developerworks.derby.ant.DBLookTask" />  <target name="demo">    <property name="DBURL" value="jdbc:derby:my/test;create=true" />    <property name="DRIVER" value="org.apache.derby.jdbc.EmbeddedDriver" />    <property name="USERID" value="" />    <property name="PASSWORD" value="" />    <property name="TEST" value="testing" />        <!-- Start the Derby database engine explicitly -->    <startDerby />    <!-- This is the default Ant sql task -->    <sql driver="${DRIVER}"         url="${DBURL}"          userid="${USERID}"          password="${PASSWORD}"          autocommit="yes"          onerror="continue"          caching="yes">      DROP TABLE TEST;      CREATE TABLE TEST (pkey int not null generated always as       identity (start with 1, increment by 1), firstfield char(10),       secondfield int);      INSERT INTO TEST (firstfield, secondfield) VALUES ('${TEST}', 10);      SELECT * FROM TEST;    </sql>        <!-- The SQL Command will leave the Derby database is a started state.         To protect the integrity of the database, you should explicitly          stop the database -->    <stopDatabase url="${DBURL}" />    <!-- Use the dblook tool to generate DDL for the tables -->    <ddlExport url="${DBURL}" dest="tables.sql" verbose="yes" />      <!-- Package the DB up for read-only distribution -->    <jar destfile="db.jar" >      <fileset dir=".">        <include name="my/**/*" />      </fileset>    </jar>    <!-- Shutdown Derby properly.  This should be done every time,         but only when you're absolutely done using Derby -->    <stopDerby />      </target>    </project>      





回页首

StartDerbyTask.java

start derby 任务负责将嵌入式数据库引擎加载到内存中,因此在 Ant 脚本中应该放在所有其他 Derby 任务的前面。根据需要,这个 SQL 任务可以在加载用于 Derby 的 JDBC Driver 时加载数据库引擎,但遵循一种更具有说明性的方法总是有益的,因为这样可以完全控制何时启动数据库。清单 2 展示了这项任务的代码。


清单 2. StartDerbyTask.java
        1  package com.ibm.developerworks.derby.ant;2  3  import org.apache.tools.ant.BuildException;4  import org.apache.tools.ant.Task;5  6  public class StartDerbyTask 7   extends Task {8    9    public void execute() 10     throws BuildException {11       try {12         Class.forName("org.apache.derby.jdbc.EmbeddedDriver");13         System.out.println("Derby has been started!");14       } catch (Exception e) {15         System.out.println(16           "Derby could not start. This is most likely " +17           "due to missing Derby JAR files. Please check your classpath" +18           "and try again.");19         throw new BuildException(e);20       }21   }22 }      

第 12 行很关键,它同时将嵌入式引擎和它的 JDBC 驱动程序装入内存。这是加载 Derby 的惟一方法,并且在每个 Java 虚拟机上 只能做一次(在一个 JVM 实例中使用多个类加载器时,这是真正惟一值得关心的事情)。

在这里,start derby 任务没有特别的参数;然而一个更健壮的版本可能允许设置各种 Derby 配置属性。





回页首

SQL Ant 任务

启动了 Derby 之后,就可以使用 SQL Ant 任务中的构建对该引擎执行各种操作。在线 Ant 文档提供了( http://ant.apache.org/manual/CoreTasks/sql.html)大量关于该任务用法的细节,因此这里没有对此花很多时间,只是指出与使用 Derby 相关的特定细节。


清单 3. SQL Ant 任务
        <sql driver="${DRIVER}"     url="${DBURL}"      userid="${USERID}"      password="${PASSWORD}"      autocommit="yes"      onerror="continue">  DROP TABLE TEST;  CREATE TABLE TEST (pkey int not null generated always as   identity (start with 1, increment by 1), firstfield char(10),   secondfield int);  INSERT INTO TEST (firstfield, secondfield) VALUES ('${TEST}', 10);  SELECT * FROM TEST;</sql>      

首先,驱动程序属性必须等于 "org.apache.derby.jdbc.EmbeddedDriver"。其次,url 属性的基本格式必须是 "jdbc:derby:databaseName",其中 databaseName 是您将使用的 Derby 数据库的名称。Derby 支持一组扩展的连接 URL 选项,例如可以说明在 JDBC 驱动程序尝试连接到数据库时是否应该动态创建数据库;是否加密数据库以及与加密过程相关的各种选项;等等。要了解关于连接字符串的完整细节,请参阅 Derby 文档。对于您的这个简单例子,构建过程使用连接 URL 值 "jdbc:derby:my/test;create=true",这样将导致在一个相对于当前路径的名为 my/test 目录中创建一个新的数据库(例如,如果您从 Windows® 的 C:/ root 下运行 ant 脚本,那么将在 C:/my/test 目录中创建数据库)。





回页首

StopDatabaseTask.java

当 SQL 任务在执行并且 Derby 被请求加载一个到 my/test 数据库的连接时,将在数据库目录中创建一个锁文件,这个锁文件将阻止 Derby 的其他实例加载数据库。当 SQL 任务完成其工作时,到 Derby 数据库的 JDBC 连接将被关闭,但不会删除这个锁文件,因为嵌入式 Derby 实例将保持与数据库的内部连接,以防有人想打开另一个连接并用该连接做更多工作。如果您知道不再需要使用数据库,或者您在构建过程中为数据库发布作准备,那么正确地关闭 Derby 与数据库的内部连接十分重要。StopDatabaseTask 就是为这一目的而设计的。


清单 4. StopDatabaseTask.java
        1  package com.ibm.developerworks.derby.ant;2  3  import java.sql.DriverManager;4  import java.util.ArrayList;5  import org.apache.tools.ant.BuildException;6  import org.apache.tools.ant.Task;7  8  public class StopDatabaseTask 9    extends Task {10 11   private ArrayList subTasks;12   13   private String url;14 15   public String getUrl() {16     return url;17   }18   19   public void setUrl(String url) {20     this.url = url;21   }22   23   public void execute() 24     throws BuildException {25       try {26         DriverManager.getConnection(url + ";shutdown=true");27       } catch (Exception e){28         System.out.println("Database has been shutdown");29       }30   }31   32 }      

第 26 行是这段代码的重要部分。通过将 "shutdown=true" 附加到数据库的 URL 中,并使用 DriverManager.getConnection,可以指示 Derby 彻底地关闭它与数据库的内部连接。通过这种方式调用该方法总是会导致抛出一个 Exception,该异常指出数据库被关闭。该任务将捕捉异常,并且正确地、清晰地向用户报告状态。





回页首

StopDerbyTask.java

当使用 Derby 完全完成 Ant 脚本时,最好关闭嵌入式数据库引擎。为此,这里提供了 StopDerbyTask。


清单 5. StopDerbyTask.java
        1  package com.ibm.developerworks.derby.ant;2  3  import java.sql.DriverManager;4  import org.apache.tools.ant.BuildException;5  import org.apache.tools.ant.Task;6  7  public class StopDerbyTask 8    extends Task {9    10   public void execute() 11     throws BuildException {12       try {13         DriverManager.getConnection("jdbc:derby:;shutdown=true");14       } catch (Exception e) {15         System.out.println("Derby has been shutdown!");16       }17   }18 }      

像在 StopDatabaseTask 中一样,通过将一个特殊的连接 URL 字符串传递给 JDBC DriverManager 的 getConnection 操作来关闭 Derby。但是,为了关闭 Derby,这个连接 URL 不能包含任何对数据库名称的引用。调用该方法总会导致一个异常被抛出,该异常指出 Derby 被成功关闭。这样,在关闭 Derby 之后,在同一个 JVM 实例中就不能再重新加载 Derby,因此在使用该任务时要小心。





回页首

DDL 生成

DBlook 是随 Derby 数据库引擎一起发布的一个重要工具,它用于生成一个数据库模式上的数据定义语言(Data Definition Language,DDL)脚本。通常该实用程序是通过命令行工具访问的。Snell 提供了一个完整的简单任务,以便您用于自己的 Ant 脚本,如下所示。


清单 6. DBLookTask.java
        1   package com.ibm.developerworks.derby.ant;2   3   import java.util.ArrayList;4   import java.util.StringTokenizer;5   import java.util.Vector;6   import org.apache.derby.tools.dblook;7   import org.apache.tools.ant.BuildException;8   import org.apache.tools.ant.Task;9   10  public class DBLookTask 11    extends Task {12  13    private String url;       // -d14    private String dest;      // -o15    private String schema;    // -z16    private Vector tables;    // -t17    private boolean append;   // -append18    private boolean verbose;  // -verbose19    private boolean noview;   // -noview20    21    public boolean isAppend() {22      return append;23    }24    public void setAppend(boolean append) {25      this.append = append;26    }27    public String getDest() {28      return dest;29    }30    public void setDest(String dest) {31      this.dest = dest;32    }33    public boolean isNoview() {34      return noview;35    }36    public void setNoview(boolean noview) {37      this.noview = noview;38    }39    public String getSchema() {40      return schema;41    }42    public void setSchema(String schema) {43      this.schema = schema;44    }45  46    public void setTables(String tables) {47      if (this.tables == null)48        this.tables = new Vector();49      StringTokenizer st = new StringTokenizer(tables, " ");50      while (st.hasMoreTokens()) {51        this.tables.add(st.nextToken());52      }53    }54    55    public String getTables() {56      StringBuffer buf = new StringBuffer();57      if (tables != null) {58        for (int n = 0; n < tables.size(); n++) {59          buf.append(tables.get(n) + " ");60        }61      }62      return buf.toString();63    }64    65    public String getUrl() {66      return url;67    }68    public void setUrl(String url) {69      this.url = url;70    }71    public boolean isVerbose() {72      return verbose;73    }74    public void setVerbose(boolean verbose) {75      this.verbose = verbose;76    }77    78    public void execute() 79      throws BuildException {80        ArrayList args = new ArrayList();81        args.add("-d");82        args.add(url);83        84        if (dest != null) {85          args.add("-o");86          args.add(dest);87        }88        89        if (schema != null) {90          args.add("-z");91          args.add(schema);92        }93        94        if (tables != null) {95          args.add("-t");96          for (int n = 0; n < tables.size(); n++) {97            args.add(tables.get(n));98          }99        }100       101       if (append)102         args.add("-append");103       104       if (verbose)105         args.add("-verbose");106       107       if (noview)108         args.add("-noview");109       110       String[] argsarray = new String[args.size()];111       argsarray = (String[])args.toArray(argsarray);112       dblook.main(argsarray);113   }114 }      

该任务惟一要做的就是将一个数据库的 DDL 输出到文件中。任务参数指定了目标文件,要包括的表的名称,是否在 DDL 中包括视图,导出时是否使用 Verbose 模式,以及要导出的特定模式的名称。

在这个例子构建脚本中,<dblook url="${DBURL}" dest="tables.sql" verbose="yes" /> 用于规定应该将由 Ant 属性 ${DBURL} 标识的用于整个数据库的 DDL 导出到一个名为 tables.sql 的文件中。导出的东西包括所有的模式、所有的表和所有的视图等等。





回页首

打包和发布

创建好数据库,并使用 StopDatabaseTask 正确地关闭该数据库后,您可以使用很多不同的方法来发布数据库。如果客户机必须拥有对数据库的完全读/写访问权,那么必须原封不动地发布文件结构,并且在客户机上解压缩(为便于传输,可以先将文件压缩,但是使用该文件之前需要在客户机上先进行解压)。但是,如果必须使用只读许可来访问数据库,那么必须先压缩文件结构,并以 JAR 文件格式发布到客户机上。这可以通过使用标准 Ant JAR 任务在 Ant 脚本中完成。


清单 7. 使用 JAR 任务打包 Derby 数据库
        <jar destfile="db.jar" >  <fileset dir=".">    <include name="my/**/*" />  </fileset></jar>      

在客户端,通过使用 JDBC 连接 URL "jdbc:derby:jar:(db.jar)my/test" 可以获得包含在 JAR 中的到数据库的只读连接。





回页首

结束语

这里介绍的 Ant 任务十分简单,并且有些不完整。Derby 还有更多的特性可以被利用,例如加密数据库的创建,对各种配置文件的支持等等,这些在本文中都没有讨论。您需要自己采用和改进这些任务,以解决自己的开发需求。






回页首

下载

描述 名字 大小 下载方法 Source files for the Derby Ant Tasks derbyant.zip 10 KB  FTP|HTTP 关于下载方法的信息 Get Adobe® Reader®



回页首

参考资料

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文

  • Derby 数据库引擎是一种开放源代码嵌入式关系数据库引擎,IBM 将其捐献给了 The Apache Software Foundation。最新版本的 Derby 数据库引擎可以从 http://incubator.apache.org/derby 下载。

  • Apache Ant 是一个强大的基于 XML 的工具,用于创建和管理构建脚本。最新的版本可以从 http://ant.apache.org 下载。

  • 欲了解关于包括 Web 服务在内(但不限于此)的新兴技术主题的更多信息,请参阅我的 developerWorks weblog




回页首

关于作者

Author photo

James Snell 是 IBM 的 Emerging Technologies Toolkit 的成员之一,在过去几年里,他的时间主要花费在了新兴的 Web 服务技术和标准上。他维护着一个关注新兴技术的 weblog,网址是 http://www.ibm.com/developerworks/blogs/dw_blog.jspa?blog=351。