内容


用 Apache Derby 进行开发 —— 取得节节胜利

使用 Apache Derby 进行数据库开发,第 1 部分

马上开始使用 Derby

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 用 Apache Derby 进行开发 —— 取得节节胜利

敬请期待该系列的后续内容。

此内容是该系列的一部分:用 Apache Derby 进行开发 —— 取得节节胜利

敬请期待该系列的后续内容。

关系数据库系统简介

您可以很快就开始开发数据库应用程序,但可能要花一生的时间来掌握它。幸运的是,Apache Derby 是轻量级数据库,您不必用毕生的精力来精通它。按照本文的下列步骤操作之后,就能够开始使用它了。

但本系列的目标不仅仅在于让您入门,而旨在帮助您掌握使用 Apache Derby。首先,应熟悉 ACID 测试,它提供了对关系数据库基本原则的压缩封装。

ACID 测试

钻石显然是十分贵重的东西,正因为贵重,所以才会严肃对待赝品被。确定钻石是真是假的一个简单而(至少在电影里)流行的测试是让它在一片玻璃上滚。因为钻石是众所周知最坚硬的材料,真正的钻石很容易切割玻璃表面;而赝品,尤其是用玻璃本身制作的赝品,则无法做到。

对软件开发人员来说,数据库也有这么贵重。如果使用数据库的话,需要确保它安全存储数据并允许您将来检索数据。您还希望数据库允许多个程序使用数据库而不会相互干扰。为了演示,假设您拥有一个银行。银行的数据库必须具备下列功能:

  • 安全存储合适的数据
  • 快速检索合适的数据
  • 支持多个并行的用户会话

这些任务可以合称为 ACID 测试;ACID 是 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)和 Durability(持久性)的缩略词。

原子性 指数据库操作可以组合到一起,当作单个单元处理。

一致性 保证此单个单元(或事务)中的所有操作要么都成功执行,要么都不执行。换句话说,数据库不能处于未完成状态。要了解这些特征为何如此重要,可考虑这样一个银行事务:即钱从储蓄帐户转到支票帐户。如果在将钱从储蓄帐户减去之后、加到支票帐户之前,转帐处理失败,那么您就会变穷,而银行将会有一个愤怒的(前)客户!原子性使得这两个操作 —— 从储蓄帐户减钱和向支票帐户加钱 —— 被当作单个事务进行处理。一致性保证事务中的这两个操作同时成功或同时失败。这样,您的钱就不会丢失了。

隔离性 指独立的数据库事务集合以不相互冲突的方式执行。仍使用这个银行类比,考虑两个客户同时在帐户之间转移资金。数据库必须分别跟踪两个转帐;否则,资金可能进入错误的帐户,而银行可能得多两个愤怒的(前)客户。

持久性 保证数据库是安全的,不会异常终止。当电源断电时,如果电视或计算机不工作,这可能是小麻烦,但同样的事情对于数据库来说就不一样了。如果银行计算机在转移资金时掉电,导致交易丢失,您就不会是个快乐的客户了。持久性保证如果数据库在资金转移期间异常终止,则当数据库重新启动时,它将能够恢复交易并继续正常的操作。

通过 ACID 测试不容小觑,许多简单的数据库都做不到。对于关键的电子商务或基于 Web 的应用程序,通过 ACID 测试是必不可少的。这就是为什么如此多的公司和个人利用企业级数据库系统(比如 IBM DB2® Universal Database、Oracle 10g 或 Microsoft® SQL Server)的原因之一。这些数据库与 ACID 测试完全兼容。与这些数据库系统相比,Apache Derby 数据库就像是被遗忘的后娘生的孩子一样。但是,Apache Derby 与 ACID 测试完全兼容,您可以放心地使用它开发基于 Web 的数据库应用程序。此外,如果开始使用 Apache Derby,而且您的应用程序(或业务)在增长,则可以毫不费力地将数据库应用程序移植到 DB2 等企业级数据库系统。

用 Apache Derby 创建数据库

在使用数据库之前,必须创建一个数据库。在 Derby 下载和安装过程中,您会获得几个工具。其中的 ij 是交互式 Java™ 工具,用于与 Apache Derby 数据库服务器通信。下文将展示如何使用 ij 工具执行简单的数据库操作,比如创建数据库。

本系列的第一篇文章 中,学习了如何下载和安装 Derby 软件。如果还没有阅读该文章,那么现在应该读一读。具体来说,按照指导进行下载和安装,才能在计算机上具有 Apache Derby 软件的一个可以工作的版本。

第一篇文章的结尾讨论了如何正确设置系统以使用 Derby 数据库。总之,因为 Derby 是 Java 应用程序,所以必须正确初始化 CLASSPATH 环境变量。可以设置 DERBY_INSTALL 环境变量,然后将相关的 Java Archive (JAR) 文件添加到 shell 初始化文件(比如 .bashrc 文件)中的 CLASSPATH 中,命令如下:

export DERBY_INSTALL='/opt/Apache/db-derby-10.1.2.1-bin'
export CLASSPATH=$DERBY_INSTALL/lib/derby.jar
export CLASSPATH=$CLASSPATH:$DERBY_INSTALL/lib/derbytools.jar:.

通过创建批处理文件可以在 Microsoft Windows® 系统上获得同样的效果,命令如下:

set DERBY_INSTALL=C:\Apache\db-derby-10.1.2.1-bin
set CLASSPATH=%DERBY_INSTALL%\lib\derby.jar
set CLASSPATH=%CLASSPATH%;%DERBY_INSTALL%\lib\derbytools.jar;.

注意:在这两个示例中,CLASSPATH 环境变量的初始化(通过 exportset shell 命令)都用两个步骤完成。这纯粹是因为本文篇幅所限。可以在自己的变量初始化中使用一行或两行。

现在只要打开新命令提示,就可以运行该批处理文件。不管是 Windows 还是 UNIX® 脚本文件,一定要确保正确指定安装 Derby 软件的目录。

正确设置了环境之后,可以运行 ij 工具来创建新的目录,如 清单 1 所示。

清单 1. 使用 ij 工具
rb$ echo $CLASSPATH
/opt/Apache/db-derby-10.1.2.1-bin/lib/derby.jar:
/opt/Apache/db-derby-10.1.2.1-bin/lib/derbytools.jar:.
rb$ mkdir derbyWork
rb$ cd derbyWork
rb$ java org.apache.derby.tools.ij
ij version 10.1
ij> connect 'jdbc:derby:test;create=true' ;
ij> exit ;
rb$ ls -CF
derby.log       test/

首先,显示 CLASSPATH 环境变量。这样做有时是避免以后出错的好办法。在这里,Derby JAR 文件明显存在。下一步是创建并更改为可以工作的新目录(在本例中目录叫做 derbyWork,但您可以随意使用任何名称)。这就更容易看清使用 ij 工具创建新数据库时发生的事情。预备工作完成之后,可以开始启动 ij 了。

因为 ij 工具是 Java 应用程序,因此需要启动 Java Virtual Machine (JVM),并指出要运行的相应主类的名称,在这里是 ji 工具。如果获得 Java 异常,则重新检查 CLASSPATH 以确保 derbytools JAR 文件存在。

当 ij 工具启动时,显示版本信息并提供提示符,提示符默认情况下是一个大于符号 (>)。在该提示符下,运行 connect 命令,连接数据库。connect 命令需要一个指示符字符串用于查找要连接的数据库。在本例中,该连接字符串是 jdbc:derby:test;create=true。正式地,该字符串称为 Java Database Connectivity (JDBC) URL。(JDBC 是一种 Java 技术,允许 Java 应用程序与数据库通信。)

对 JDBC URL 的完全分析超出了本文范围(请参阅 参考资料 部分获得更多信息)。但是,本例十分简单,可分解如下:

  • jdbc 是 ij 工具与数据库服务器通信的机制。
  • derby 是 JDBC 驱动程序类的名称,ji 工具使用该类与数据库服务器通信。
  • test 是要创建的数据库名称。
  • create=true 是应传递给 Derby JDBC 驱动程序的特定属性。 JDBC 属性列在 URL 其他部分的后面,并用分号分隔。

要正确访问,必须将 JDBC URL 作为字符串传递给 connect 命令;因此需要将其封装在单引号 (') 字符里。最后,告诉 ij 工具处理命令,必须添加分号(因为 ji 是 Java 工具)并按下 Return。在短暂的延迟之后,ij 工具提供一个新提示符。那就是 —— 新数据库已创建。

想知道发生了什么,使用 exit 命令(别忘了分号)退出 ij 工具,查看运行 ij 工具的目录(在 UNIX 系统上使用 ls 命令,在 Windows 系统上使用 dir 命令)。这样就生成一个新文件以及一个新目录,叫做 test,它与在 JDBC URL 中为数据库命名的名称相匹配。

如果感到好奇的话,可以研究为您的数据库创建的 test 目录,如 清单 2 所示。(目录的名称和内容可能与这里显示的稍有不同。)

清单 2. test 目录的内容
rb$ ls -CF test/
log/                    seg0/                   service.properties  
rb$ ls -CF test/log/
log.ctrl        log1.dat        logmirror.ctrl
rb$ ls -CF test/seg0/ 
c10.dat         c191.dat        c221.dat        c2c1.dat       c90.dat
c101.dat        c1a1.dat        c230.dat        c2d0.dat       ca1.dat
c111.dat        c1b1.dat        c241.dat        c2e1.dat       cb1.dat
c121.dat        c1c0.dat        c251.dat        c2f0.dat       cc0.dat
c130.dat        c1d1.dat        c260.dat        c31.dat        cd1.dat
c141.dat        c1e0.dat        c271.dat        c41.dat        ce1.dat
c150.dat        c1f1.dat        c281.dat        c51.dat        cf0.dat
c161.dat        c20.dat         c290.dat        c60.dat
c171.dat        c200.dat        c2a1.dat        c71.dat
c180.dat        c211.dat        c2b1.dat        c81.dat

研究这些目录时,可能会对创建新目录时发生的所有动作感到吃惊。但要记住,Apache Derby 是 ACID 兼容的数据库,因此,后台发生了好多事情。数据库主目录(本例中为 test)内有一个 log 目录、一个 seg0 目录和一个属性文件。log 目录保存特定于数据库的日志文件,这些文件允许 Derby 记录在一组数据库操作(一个事务)期间发生的操作。如果 Derby 数据库服务器在操作期间由于某种原因终止,则它可以保存停止的位置,并将数据库恢复到正常状态。

在本例中,seg0 目录保存将用于测试数据库的数据文件。很奇怪,所有这些文件都是在数据库刚刚创建时生成的,推测起来应该是空的。原因非常简单:当数据库存储数据时,它不仅创建一个新的文件,还会将数据转储到该文件中。由于性能原因(并满足 ACID 测试),数据库将数据分摊到许多文件中。数据在写入文件时具有特定的结构,称为页面。数据页面的内容包括页面上的数据和有关页面上数据的信息(有时称为元数据)。通过在数据库首次创建时生成所有这些文件(和文件中的页面),数据库可以开始尽快地存储数据。

ij 工具

ij 工具功能十分强大。可用它(在将来的文章中)执行范围广泛的操作,包括创建数据库(如前所述)和在数据库内创建新项。ij 工具包括一个 help 命令,可以列出和描述要使用的一些常见命令,如 清单 3 所示。注意,为了适应空间限制,该清单已被重新格式化,所以您的版本看起来可能稍有不同。

清单 3. 获得 ij 工具的帮助
rb$ java org.apache.derby.tools.ij
ij version 10.1
ij> help ;
 
 Supported commands include:
 
  PROTOCOL 'JDBC protocol' [ AS ident ];
                               -- sets a default or named protocol
  DRIVER 'class for driver';   -- loads the named class
  CONNECT 'url for database' [ PROTOCOL namedProtocol ] 
                             [ AS connectionName ];
                               -- connects to database URL
                               -- and may assign identifier
  SET CONNECTION connectionName; -- switches to the specified 
                                    connection
  SHOW CONNECTIONS;            -- lists all connections
  AUTOCOMMIT [ ON | OFF ];     -- sets autocommit mode for the 
                               -- connection
  DISCONNECT [ CURRENT | connectionName | ALL ];
                               -- drop current, named, or all 
                               -- connections; the default is CURRENT
 
  COMMIT;                      -- commits the current transaction
  ROLLBACK;                    -- rolls back the current transaction
 
  PREPARE name AS 'SQL-J text'; -- prepares the SQL-J text
  EXECUTE { name | 'SQL-J text' } [ USING { name | 'SQL-J text' } ] ;
                               -- executes the statement with 
                               -- parameter values from the USING 
                               -- result set row
  REMOVE name;                 -- removes the named previously 
                               -- prepared statement
 
  RUN 'filename';              -- run commands from the named file
 
  ELAPSEDTIME [ ON | OFF ];    -- sets elapsed time mode for ij
  MAXIMUMDISPLAYWIDTH integerValue;
                               -- sets the maximum display width for
                               -- each column to integerValue
 
  ASYNC name 'SQL-J text';     -- run the command in another thread
  WAIT FOR name;               -- wait for result of ASYNC'd command
 
  GET [SCROLL INSENSITIVE] CURSOR name AS 'SQL-J query';
                               -- gets a cursor (JDBC result set) 
                               -- on the query
                               -- SCROLL cursors are only available 
                               -- in JDBC 2.0 and higher. 
                               -- (Cursor scroll type is ignored in 
                               -- JDBC 1.X.) 
  NEXT name;                   -- gets the next row from the 
                               -- named cursor
  FIRST name;                  -- gets the first row from the 
                               -- named scroll cursor
  LAST name;                   -- gets the last row from the 
                               -- named scroll cursor
  PREVIOUS name;               -- gets the previous row from the 
                               -- named scroll cursor
  ABSOLUTE integer name;       -- positions the named scroll cursor
                               -- at the absolute row number
                               -- (A negative number denotes 
                               -- position from the last row.) 
  RELATIVE integer name;       -- positions the named scroll cursor 
                               -- relative to the current row
                               -- (integer is number of rows)
  AFTER LAST name;             -- positions the named scroll cursor 
                               -- after the last row
  BEFORE FIRST name;           -- positions the named scroll cursor 
                               -- before the first row
  GETCURRENTROWNUMBER name;    -- returns the row number for the 
                               -- current position of the named 
                               -- scroll cursor (0 is returned when 
                               -- the cursor isn't positioned 
                               -- on a row.) 
  CLOSE name;                  -- closes the named cursor
  LOCALIZEDDISPLAY [ ON | OFF ];
                               -- controls locale sensitive data 
                               -- representation
 
  EXIT;                        -- exits ij
  HELP;                        -- shows this message
 
 Any unrecognized commands are treated as potential SQL-J commands 
 and executed directly.
 
ij>

清单 3 所示的大多数命令似乎都很陌生,当然啦,您还刚开始学习 Apache Derby。

还可以使用 ij 工具与数据库建立多个连接,如 清单 4 所示。

清单 4. 用 ij 工具建立连接
ij> connect 'jdbc:derby:test;create=true' ;
WARNING 01J01: Database 'test' not created, 
connection made to existing database instead.
ij> connect 'jdbc:derby:test' ;
ij(CONNECTION1)> show connections ;
CONNECTION0 -   jdbc:derby:test
CONNECTION1* -  jdbc:derby:test
* = current connection
ij(CONNECTION1)> disconnect ;
ij> show connections ;
CONNECTION0 -   jdbc:derby:test
No current connection
ij> set connection CONNECTION0 ;
ij> show connections ;
CONNECTION0* -  jdbc:derby:test
* = current connection
ij> exit ;

本例首先尝试使用原始的 JDBC URL 连接测试数据库。但是获得一个警告,因为测试数据库已经存在。代码发出一个新 connect 命令以更改 JDBC URL,从而去掉 ;create=true JDBC 属性。这时没有发出警告,但提示符更改为包括一个 (CONNECTION1) 字符串。这看起来不太正常,因为在第一次创建测试数据库时没有发生这种情况。

该结果说明,尽管有警告,但创建数据库连接的第一次尝试成功了。为了展示已经有到同一数据库的两个连接,发出 show connections ; 命令,将显示两个连接、关联的 URL 以及当前连接(在本例为 CONNECTION1)。

现在不需要到同一数据库的两个连接,因此可以使用 disconnect ; 命令关闭当前连接。发出另一个 show connections ; 命令将显示当前惟一打开的连接,但还会看到没有当前连接。因为需要具有活动的或当前的连接向特定数据库发送命令,所以应该相应地更改当前连接。使用 set connections 命令,将目标连接名称作为最终参数,可以容易地实现这一点。现在,发出另一 show connections ; 命令时,将看到当前连接的列表以及当前连接的名称。最后,发出 exit ; 命令断开所有当前连接并终止 ij 工具。

结束语

本文介绍了关系数据库,并侧重于 ACID 测试。ACID 测试允许开发人员测量数据库系统的利用率。如果需要基于 Java 的轻量级数据库来支持通过 ACID 测试需要的完整能力,则应采用 Apache Derby 数据库。本文还介绍了 Derby 数据库附带的 ij 工具。ij 工具可用于连接数据库并向数据库发出命令。本文使用 ij 工具创建了一个新数据库,然后研究了 Derby 创建新数据库时生成的目录和文件。

查看本系列的下一期文章,将会获得使用模式进行数据库开发的全面概述。


相关主题

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文
  • 阅读本系列的第一篇文章 “用 Apache Derby 进行开发 ―― 取得节节胜利:Apache Derby 介绍” (developerWorks,2006 年 2 月),获得有关如何下载和安装 Apache Derby 软件的说明。
  • 从 Apache Derby Project 主页下载 Apache Derby
  • 访问官方 JDBC 主页,获得有关 JDBC 的详细信息。
  • 从许多 Apache Derby 项目的联机 手册,获得有关如何使用 Apache Derby 数据库的详细信息。
  • 参阅 Apache Derby 项目的 教程,获得有关如何下载和安装 Apache Derby 的详细信息。
  • 访问 Apache Derby 项目网站上的 有用讨论,学习如何正确验证下载。
  • 查阅 developerWorks Apache Derby 项目专区,获得入门 Derby 的文章、教程和其他资源。
  • 下载 IBM Cloudscape™,这是等同于 Apache Derby 的功能,包括支持、文档、安装程序和示例。但是,Derby 和 Cloudscape 中的基础数据库引擎是相同的。
  • 浏览 developerWorks 开放源码专区中所有可用的 Apache 文章Apache 免费教程
  • Safari 书店 浏览各种技术主题的书籍。

评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source, Information Management
ArticleID=156429
ArticleTitle=用 Apache Derby 进行开发 —— 取得节节胜利: 使用 Apache Derby 进行数据库开发,第 1 部分
publish-date=08282006