技术开发 频道

在JRuby中构建Apache Derby数据库应用程序的两种方法

【IT168技术文档】{$PageTitle=关于本教程}
Robert Thornton 有六年的 Java 语言开发经验,目前是 Daugherty Business Solutions 的顾问。他担任在 St. Louis, Mo., 领域的各种客户机上应用 Java EE 应用程序的开发人员和架构师,擅长面向对象的开发并且在工作中主要使用 Java 和 C++ 语言。

JRuby是运行在Java™ 虚拟机(Java™ Virtual Machine,JVM)中的Ruby编程语言的实现。本教程演示了如何安装和配置JRuby以连接至Apache Derby数据库。随着Ruby和Ruby on Rails变得越来越流行,JRuby成为一种广受关注的技术,在使用诸如简单的语法和闭包之类的Ruby功能时利用JVM的可移植性、安全性和类库。如果编写的是需要关系数据库的小型应用程序,或者需要能够随产品配送数据库,则Derby数据库是持久性机制的非常好的选择。本教程将向您展示连接至JRuby并从JRuby构建Derby数据库应用程序的两种方法。

开始之前

关于本教程

Apache 的 Derby 数据库是一个小型的内存中数据库,它是用作嵌入式数据库的理想选择。(参考资料 部分列出了 Derby 的完整介绍的链接。)

JRuby 是 Ruby 编程语言的纯 Java 实现。Ruby 是一种面向对象的脚本语言,适用于各种系统管理脚本、富 Internet 应用程序或者桌面应用程序。JRuby 的当前版本为 JRuby 0.9(写作本文时),因此它几乎涵盖了标准的基于 C 的 Ruby 解析程序中的所有功能。如果要将 JRuby 用于生产,则仍有一些限制需要注意,但是 JRuby 在大多数情况下都可以正常使用。JRuby 项目的两名高级开发人员最近被 Sun 雇佣,因此您可以期待 JRuby 项目将来的开发动力依然会源源不绝。由于 JRuby 位于 JVM 中,因此可以使用 Java 类库并且可以执行在 Ruby 中实现 Java 接口之类的操作。

本教程介绍了一些 JRuby 基础知识以及如何使用 Derby。参考资料 部分列出了 developerWorks 中关于 JRuby 的介绍性文章以及其他的 JRuby 教程,前者描述了截至 2004 年 JRuby(版本 0.7)的很多功能。

目的

本教程的目的在于展示如何通过 JRuby 解析程序连接并使用 Apache Derby 数据库。您将了解通过 JRuby 如何将数据插入 Derby 以及如何从 Derby 中检索数据。下面提供了与 Derby 进行交互的两种方法:

  1. 在 JRuby 中通过 Ruby 使用 JDBC
  2. 使用 Ruby 的 ActiveRecord 库(通过 ActiveRecord-JDBC 库),该库曾经作为 Ruby on Rails 的一部分开发,但是可独立用于对象关系映射(Object-Relational Mapping,ORM)

先决条件

本教程适用于熟悉 Java 代码和 JDBC 的开发人员。不要求具备 Ruby 方面的使用经验,但是懂脚本语言(Perl、Python、Ruby 等等)将使您可以更轻松地理解语法。您无需任何特定的集成开发环境 (IDE) 或工具知识。要求熟悉文本编辑器和设定环境变量。

系统要求

要运行本教程中的示例,系统必须能够运行 JVM。本教程假定 Java 环境已成功配置,因此要先下载并安装 JVM,然后再继续学习本教程。

这一次,需要能够从命令行运行 Subversion 才能完成本教程的 ActiveRecord 部分。如果需要执行 ActiveRecord 示例,则要先下载 Subversion 客户机(有关链接,请参阅 参考资料 部分),然后再继续学习本教程。

JRuby 入门

安装 JRuby,然后编写第一个 JRuby 脚本。

安装 JRuby

安装 JRuby 是一个十分简单的过程,包括解压缩分发和设定环境变量。

  1. 从 JRuby 主页下载 JRuby(请参阅 参考资料),并将其解压缩到选定目录中。
  2. 将 JRUBY_HOME 环境变量设为 JRuby 所解压缩到的目录。例如,set JRUBY_HOME=c:\java\jruby
  3. 最后,将 JRUBY_HOME 添加到 PATH 环境变量中。

编写简单的 JRuby 脚本

现在编写一个简单的 JRuby 脚本来检验环境是否已正确配置并首次查看 JRuby 的 Ruby 特征和 Java 特征。

  1. 打开文本编辑器,并创建一个包含下面一行代码的文件:puts 'Hello World'

在 Ruby 中,puts 是打印字符串的一种方法。把它看作输出字符串。这行代码等效于下面的一行 Java 代码:System.out.println("Hello World")。(有关 Ruby 的介绍性文章,请参阅“脱离 Rails 看 Ruby”教程 [developerWorks,2005 年 12 月]。)

  1. 将文件另存为 helloWorld.rb,并且返回到命令行。在此脚本上运行 JRuby 应当会显示以下结果:

jruby helloWorld.rb

     Hello World

这个结果告诉您 JRuby 已成功激活 JVM 并在其中执行了 Ruby 脚本。下一步是确保可以访问 Java 类,从而可以使用 JDBC 来连接到 Derby。

  1. 将清单 1 中所示的三行添加到 helloWorld.rb 文件中:

清单1:确保能访问 Java 类

            

require 'java'

include_class("java.lang.System")

System.out.println("Hello Java World")

当从 JRuby 脚本调用 Java 类时,需要明确地告诉 JRuby 将要引用哪些类或软件包。使用诸如 include_class 之类的 JRuby 方法可以完成该操作。要将那些 JRuby 方法导入脚本中,请使用上面的第一行(require 'java')。请将 require 视为 import 的 Ruby 等效命令。由于需要访问一个类 java.lang.System,因此需要告诉 JRuby 将要做的操作。包含该类后可以在其上引用 out.println。最后一行可以从 Java 程序中直接复制出来。

4.像以前一样从命令行运行此脚本,则应当会得到以下输出:

Hello World

Hello Java World

现在您测试了在 JRuby 中编写 Ruby 代码并且调用了 Java 类。JRuby 还有除了目前您看到的功能之外的大量功能。例如,可以在 Ruby 中实现 Java 接口。(有关 JRuby 的更详细的介绍,请参阅 参考资料 部分。)


使用 JDBC 连接至 Derby

此部分将说明如何安装 Derby 以及如何使用 JRuby 和 JDBC 连接至 Derby。

安装 Derby

要安装 Derby,请执行以下步骤:

  1. 从 Derby 主页下载 Derby,然后将其解压缩到目录中。解压缩后,必须创建一个环境变量并更新另一个环境变量。
  2. 创建环境变量 DERBY_INSTALL,并将其设为解压缩后 Derby 所在的目录(例如,set DERBY_INSTALL=c:\java\db-derby-10.1.3.1-bin)。
  3. 接下来,更新 CLASSPATH 以包含两个 JAR 文件:derby.jar 和 derbytools.jar。这两个文件可在 DERBY_INSTALL 中的 lib 文件夹中找到(例如,set CLASSPATH=%DERBY_INSTALL%\lib\derby.jar;%DERBY_INSTALL%\lib\derbytools.jar;%CLASSPATH%)。

现在应当通过尝试使用 Derby 附带的 ij 命令行工具连接到 Derby 来检验 Derby 是否已安装并正确配置。

  1. 回到创建的 JRuby 脚本所在的目录。通过输入以下命令来运行 ij:java org.apache.derby.tools.ij。应当会获得一条显示 ij version 10.1 的消息。
  2. 现在将创建数据库供本教程的其余部分使用。将以下命令输入 ij:ij> connect 'jdbc:derby:JRubyDB;create=true';。此时,创建了一个名为 JRubyDB 的保存数据库的目录。
  3. 现在创建了数据库,可以创建一张表并向其中插入一些数据,从而可以在 JRuby 中检索这张表。为此,请执行清单 2 中所示的代码行(仍在 ij 内)。

清单2:创建一张表在 JRuby 内检索   

            

create table employees (id integer,

name varchar(50),

title varchar(100),

office varchar(20));

insert into employees values (1, 'Fred Smith', 'CEO', '1');

insert into employees values (2, 'John Doe', 'Vice President', '2 West');

insert into employees values (3, 'Jane Jones', 'CFO', '2 East');

insert into employees values (4, 'Sam Smiles', 'Intern', '99');

insert into employees values (5, 'Julie Morgan', 'Sales Associate', '5 West');

insert into employees values (6, 'Wilma Fonda', 'Executive Assistant', '23');

insert into employees values (7, 'Danielle Jamison', 'Director of Marketing', '3 East');

insert into employees values (8, 'Michele Cannon',

'Director of Customer Support', '5 East');

insert into employees values (9, 'Lance Hanniford', 'CIO', '3 West');

insert into employees values (10, 'Eliot Rinaggio', 'Sales Associate', '5 West');

连接至 Derby

由于已创建数据库并用一些数据对其进行了填充,下一个任务是使用 JRuby 连接至该数据库。为此,需要新建一个名为 derby.rb 的文件。在文本编辑器中打开此文件,并输入清单 3 中所示的代码行。

清单3:创建 derby.rb

            

require  'java'

module JavaSql

include_package 'java.sql'

end

include_class("java.lang.Class") { |packagename, classname| "J" + classname}

JClass.forName("org.apache.derby.jdbc.EmbeddedDriver")

connection = JavaSql::DriverManager.getConnection("jdbc:derby:JRubyDB;create=true",

"",

"")

第一行没有新内容,但是其余代码显示了 JRuby 的一些新部分:

module JavaSql 行 —— 模块是可以看作是名称空间的 Ruby 元素。它们允许将方法、类和常量分组到一起。本文中,将创建一个 Ruby 模块,您将向其中放入 java.sql 中的所有类。由于使用的是 java.sql 软件包中的许多类,因此包含整个软件包是有道理的。请记住,包含软件包将降低脚本的运行速度。这样使用模块是访问所有这些类的便利方法。

include_class 代码行 —— 值得注意的下一行是 include_class。这是一个不同版本的 include_class 方法,因为其中使用了 Ruby 的块语法。include_class 方法将接受一个代码块(有关代码块的更多信息,请参阅 参考资料 部分中列出的一个 Ruby 教程),该代码块将用于把 Java 类 Class 重命名为 JClass。这样做是因为 Ruby 也有一个名为 Class 的类;如果不将 Java 类重命名,则会产生冲突。本文的代码块将 J 加在 Java 类名的前面。因而,Class 成为 JClass

JClass.forNameconnection 代码行 —— 上两行代码几乎与在纯 Java 代码中编写的完全相同。首先,惟一的差别是使用 JClass 来引用上一行中包含的 Java 版本的类 Class。最后一行与纯 Java 代码有两个主要差别:

◆首先,无需声明 connection 变量的类型。Ruby 是动态类型的语言;因而在变量声明中无需声明类型。

◆其次,使用上面定义的用于容纳 DriverManager 类的 JavaSql 模块。该类以及 java.sql 软件包中的所有其他内容都被 JavaSql 模块包含了进来。因而,需要在所有对该软件包中的类的引用前面加上 JavaSql::。这是一种作用域机制,与 C++ 中的一样。

只要一切设置正确,脚本应当能够运行。经过授权后,该脚本还没有任何值得注意的表现。运行它后,应当得不到任何输出。如果发生异常,请返回并查看先前的步骤以确保未遗漏任何操作。


处理 JRuby 中的 JDBC 异常

您的代码与 Java 代码之间还有另一个区别尚未提及:尚未执行任何操作来处理异常。Class.forNameDriverManager.getConnection 都抛出已检查异常。在 Java 代码中,等效代码将不会编译,直至对那些异常做出一些处理。Ruby 没有已检查异常,因此您不用处理它们。但是,编写应用程序时,通常希望执行一些处理异常的操作(如果可以)。执行代码可能产生两个已检查异常:ClassNotFoundExceptionSQLException。要了解如何处理这两个异常,请修改 .rb 文件以匹配清单 4 中所示的代码。

清单4:处理异常

            

require  'java'

module JavaSql

include_package 'java.sql'

end

include_class("java.lang.Class") { |packagename, classname| "J" + classname}

include_class("java.lang.ClassNotFoundException")

begin

JClass.forName("org.apache.derby.jdbc.EmbeddedDriver")

connection = JavaSql::DriverManager.getConnection("jdbc:derby:JRubyDB;create=true",

          "",

          "")

rescue ClassNotFoundException

puts "ClassNotFoundException"

rescue JavaSql::SQLException

puts "SQLException"

end

"")

第一个更改是为 ClassNotFoundException 添加了 include_class。由于将处理该异常,因此脚本需要知道异常类的存在。无需为 SQLException 单独使用一个 include,因为已通过 include_package 'java.sql' 包含该异常。Ruby 中的异常是按照类似于 Java 的方法来处理的。您有一个开头为 begin 而不是 try、结尾为 end 而不是 } 的块。使用 rescue,而不是使用 catch。那些更改就是与第一个版本的代码的其余差别。代码的流程应当看起来仍然熟悉。rescue 块中做的全部操作就是打印异常类型。很明显,在现实世界中您将对那些异常做一些更有用的操作,但是这将引领您入门。

第一个更改是为 添加了 。由于将处理该异常,因此脚本需要知道异常类的存在。无需为 单独使用一个 include,因为已通过 包含该异常。Ruby 中的异常是按照类似于 Java 的方法来处理的。您有一个开头为 而不是 、结尾为 而不是 的块。使用 ,而不是使用 。那些更改就是与第一个版本的代码的其余差别。代码的流程应当看起来仍然熟悉。 块中做的全部操作就是打印异常类型。很明显,在现实世界中您将对那些异常做一些更有用的操作,但是这将引领您入门。

使用 JDBC 与数据进行交互

在此部分中,将了解如何用 Derby 和 JDBC 检索和插入数据,以及如何通过 JRuby 使用 JDBC 事务。

使用 JRuby 从 Derby 检索数据

既然可连接至 Derby,下一步是使用 JDBC 提取数据。在 JRuby 中执行此操作的代码类似于纯 Java 代码 —— 仍要编写 JDBC 代码,只是通过另一种语言来调用它。必要的步骤包括:创建一条语句,执行查询,并迭代 ResultSet。创建连接后,需要将清单 5 中所示的五行代码添加到代码中。像以前一样,无需声明变量的类型。这段代码几乎与纯 Java 代码完全相同。惟一的差别在于略微更改循环语法以及使用 puts 而不使用 System.out.println

清单5:使用 JDBC 从 Derby 中检索数据

            

stmt = connection.createStatement()

rs = stmt.executeQuery("select name from employees")

while (rs.next()) do

puts rs.getString("name")

end

使用 PreparedStatement 也很简单。用清单 6 中所示的代码行替代上面几行代码中的前两行。

清单6:使用 PreparedStatement 

            

preparedStmt=connection.prepareStatement("select name from employees where name like ?")

preparedStmt.setString(1, "J%")

rs = preparedStmt.executeQuery()

应当会得到以下输出:

应当会得到以下输出:

John Doe

Jane Jones

Julie Morgan

使用 JRuby 将数据插入 Derby

插入数据同样简单。使用 JDBC,先检索连接,然后添加清单 7 中所示的两行。

清单7:插入数据

            

insertStmt = connection.createStatement()

insertStmt.execute("insert into employees values (11,

'James Cotton',

'Research Associate',

'Lab 1')");

运行代码后,应当会打印以下结果:

运行代码后,应当会打印以下结果:

John Doe

Jane Jones

Julie Morgan

James Cotton

更新和删除都遵循相同的范式,使用 Statement 或 PreparedStatement。

使用 JDBC 事务

通常,修改数据库中的数据时,需要使用事务来保证更改都是在一个逻辑块中做出的。JDBC 的事务都可在 JRuby 中访问。在清单 8 中所示的示例中,调用 connection.setAutoCommit(false) 将启动事务,而调用 connection.rollback() 将回滚该事务。类似地,使用 connection.commit() 来提交事务。

清单8:通过 JDBC 用 JRuby 调用 Derby

            

connection = JavaSql::DriverManager.getConnection("jdbc:derby:jrubyDB;create=true",

"",

"")

connection.setAutoCommit(false)

insertStmt = connection.createStatement()

insertStmt.execute("insert into employees values (11,

'James Cotton',

'Research Associate',

'Lab 1')");

connection.rollback()

正如您所见,通过 JDBC 用 JRuby 调用 Derby 很简单并且几乎与使用纯 Java 代码完全相同。

在 JRuby 中使用 JDBC 的其他方法

到目前为止,编写了从 Ruby 调用 JDBC 的代码。从 JRuby 与 Derby 进行交互还有其他几种方法:

纯 Java 代码 —— 数据库访问代码可以用纯 Java 代码编写。您可以有一个希望嵌入 Ruby 的应用程序,可能允许用户在应用程序中编写一些脚本。此应用程序已经有一组用于执行所有必需的数据库访问的类。需要用户编写的脚本能够通过现有数据库访问对象来访问数据库。使用 JRuby,需要执行的全部操作就是使用 include_class 和 include_package 方法从 Ruby 脚本访问那些对象。这将让您只需编写一次数据库访问代码,而不用使用两种语言重新创建该代码。

ORM 工具 —— 与 Derby 进行交互的另一种方法是使用 ORM 工具。为此,可直接从 JRuby 使用一个 Java 的 ORM 库(例如,Hibernate 或 iBatis),或者通过编写的 Java 数据库访问对象来使用 Java 的 ORM 库。使用 ORM 工具的另一种方法是使用 Ruby 中编写的众多 ORM 工具之一 —— 目前最著名的是 ActiveRecord。

使用 ActiveRecord 连接至 Derby

此部分将说明如何使用 Ruby 的 ActiveRecord 库连接至 Apache Derby。

什么是 ActiveRecord?

ActiveRecord 是用纯 Ruby 编写的 ORM 库。它是 Active Record 设计范式的一个实现,如 Martin Fowler 在 Patterns of Enterprise Application Architecture 中所述(有关 Safari 书店 Web 站点上本书的链接,请参阅 参考资料)。ActiveRecord 是著名的用于 Ruby on Rails(常见的 Web 开发框架)的默认持久性机制。但是,ActiveRecord 不需要使用 Rails 框架。其惟一依赖的是名为 ActionSupport 的软件包;因而可以在 Rails 应用程序外部使用 ActiveRecord。

直到最近,使用 Derby 的 JRuby 开发人员还不能使用 ActiveRecord,因为 ActiveRecord 不提供本机 Derby 支持或任何 JDBC 支持。但是,JRuby 开发团队现在发布了 ActiveRecord-JDBC 库的首个版本。此库向 ActiveRecord 中添加了 JDBC 支持。虽然它仍处于初级阶段,但是此项目已经支持 Derby 数据库。库是新的,因此它还有一些限制,但是它在大多数情况下运行正常。ActiveRecord-JDBC 正处于主要开发阶段,因此可以期待很快会提供更多支持(对 Derby 和其他数据库)。

安装 ActiveRecord

ActiveRecord 和 ActiveRecord-JDBC 库都是作为 RubyGems 分发的。RubyGems 是一个 Ruby 的软件包管理器(该管理器拥有用于分发程序和库的标准格式),也是一个用于轻松安装、更新和删除程序和库的工具。JRuby 0.9 没有为 RubyGems 提供足够健壮的支持,以便执行所需的操作来独立运行 ActiveRecord。当下一个版本的 JRuby 推出时,支持独立运行应当不会有问题。在过渡期间,要在 JRuby 中利用 ActiveRecord,需要从 Subversion 存储库注销 JRuby:

  1. 为 JRuby 源代码创建一个目录,并将 JRUBY_HOME 环境变量设为新目录。
  2. 在该目录中打开命令提示符,并执行以下命令(假定 Subversion 客户机位于 PATH 中):svn co svn://svn.codehaus.org/jruby/trunk/jruby %JRUBY_HOME%

此命令将把最新的 JRuby 代码下载到计算机中。下载完源代码后,需要构建它:

  1. 输入命令 ant compile。要验证下载内容,也可以输入 ant test。如果获得消息 BUILD SUCCESSFUL,则知道安装没有问题。

现在需要获得两个 gem。首先需要使用 ActiveRecord 本身执行以下操作:

  1. 通过输入 gem install activerecord --no-ri --no-rdoc 下载 ActiveRecord。如果计算机上安装了 Ruby 和 JRuby,而且 Ruby 已在 JRuby 前面的路径中,则需要使用完整路径才能执行 gem 命令,如 %JRUBY_HOME%\bin\gem install activerecord --no-ri --no-rdoc

这将安装 ActiveRecord 和 ActiveSupport,ActiveRecord 所依赖的 gem。--no-ri--no-rdoc 用于告诉 JRuby 不为 gem 生成文档。应当添加这些命令,因为 JRuby 在执行这些任务时目前很慢。(如果需要查看 ActiveRecord 或 ActiveSupport 的文档,请参阅 参考资料 部分中的链接)。

接下来,需要 ActiveRecord-JDBC gem。

  1. 执行以下命令下载并安装 ActiveRecord-JDBC gem:gem install ActiveRecord-JDBC --no-ri --no-rdoc。完成安装后,将获得以下输出:Successfully installed ActiveRecord-JDBC, version 0.2.1

用 ActiveRecord 连接至 Derby 必须使用 ActiveRecord-JDBC 0.2.1 或更高版本。现在您已经可以使用 ActiveRecord 了。

0
相关文章