Apache Derby 进行数据库开发:工具使用

2022-04-08 00:00:00 数据库 连接 命令 文件 工具

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 环境变量的初始化(通过 export 或 set 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 工具。

相关文章