H2 Database Engine Documentation 《H2 Database 教程》

命令行工具

H2数据库提供了一组命令行工具,如果你需要了解这些工具,使用参数-?,如:

java -cp h2*.jar org.h2.tools.Backup -?

命令行工具有:

  • Backup 创建数据库备份
  • ChangeFileEncryption 允许改变文件加密密码和数据库的加密算法
  • Console 启动基于浏览器的 H2 控制台
  • ConvertTraceFile 转换 .trace.db 文件到 Java 应用和 SQL 脚本
  • CreateCluster 从一个独立的数据库服务创建集群
  • DeleteDbFiles 删除所有的数据库文件
  • Recover 恢复损坏的数据库
  • Restore 从数据库备份中恢复数据库
  • RunScript 运行数据库 SQL 脚本
  • Script 为数据库备份或迁移导出 SQL 脚本
  • Server 启动 H2 服务模式
  • Shell 命令行工具

这些工具也能在程序中通过调用相应的方法来使用,相关详细的调用说明,请参考 JavaDoc 文档。

Shell 工具

Shell 工具是最简单的命令行工具,开始时,输入:

java -cp h2*.jar org.h2.tools.Shell

你会要求输入数据库URL、JDBC 驱动、用户名和密码。连接设置也可以作为命令行参数设置。连接后,你会得到的列表选项。内置命令不需要以分号结束,但只是执行 SQL 语句,需要以分号 ;作为结束。这允许输入多行语句:

sql> select * from test
...> where id = 0;

默认情况下,结果是打印成表。结果有许多列,考虑使用模式列表:

sql> list
Result list mode is now on
sql> select * from test;
ID  : 1
NAME: Hello

ID  : 2
NAME: World
(2 rows, 0 ms)

使用 OpenOffice 基础框架

OpenOffice.org 基础框架支持通过 JDBC 连接数据库。你也可以通过 OpenOffice 框架连接到 H2 数据库。首先将 JDBC 驱动增加到 OpenOffice 中,下面的步骤可以连接到H2数据库:

  • 启动 OpenOffice Writer,进入[Tools], [Options]
  • 确认你在 OpenOffice.org/Java 中选择了 JAVA 运行环境
  • 单击 [Class Path...], [Add Archive...]
  • 选择你的 h2 的 jar 文件(本机上的路径可以由你选择)
  • 单击 [OK] (按要求的点击), 停止OpenOffice (包括 Quickstarter)
  • 启动 OpenOffice 框架
  • 连接到一个存在的数据库;选择 [JDBC]; [Next]
  • 输入数据库URL,如: jdbc:h2:~/test
  • 输入 JDBC 驱动类: org.h2.Driver

你可以访问存于用户当前目录的数据库。

使用 H2 数据通过 NeoOffice (去掉 X11 的 OpenOffice):

  • 在 NeoOffice,到[NeoOffice], [Preferences]
  • 在[NeoOffice]页下找到[Java]
  • 单击[Class Path], [Add Archive...]
  • 选择 h2 的 jar 文件(本地目录,任你选择合适的目录)
  • 单击[OK](根据需要),重启 NeoOffice

现在,你可以通过"Database Wizard"创建一新的数据库:

  • 单击[File], [New], [Database]
  • 选择[Connect to existing database],并且选择[JDBC],单击next
  • 输入数据源的URL,例如:jdbc:h2:~/test
  • JDBC驱动类: org.h2.Driver

其他的在 NeoOffice 中使用 H2 的方法:

  • 将 H2 的 jar 包打包到一个扩展包中
  • 在 NeoOffice 中作为扩展 Java 包进行安装

这个能通过使用 NetBeans OpenOffice 插件来创建。详细看Extensions Development

Java Web Start / JNLP

当使用 Java Web Start / JNLP(JAVA网络加载协议),允许访问标签必须被设置在 .jnlp 文件,并且 .jar 的应用文件必须被签名,否则,当你试着去写文件系统,下面的异常将会被抛出:java.security.AccessControlException: 拒绝访问 (java.io.FilePermission ... read). 如访问标签:

<security>
    <all-permissions/>
</security>

使用连接池

如果 H2 的数据库已经打开,打开一个连接很快。如果要打开和关闭许多连接,使用连接池,可以提升性能。H2 包含了一个简单的连接池,它是基于Christian d'Heureuse 的 Mini Connection Pool Manager 。还有其他更复杂的开源连接池可以使用,如Apache Commons DBCP。H2 从内置连接池获取连接比使用DriverManager.getConnection()快两倍左右。内置的连接池使用方法如下:

import java.sql.*;
import org.h2.jdbcx.JdbcConnectionPool;
public class Test {
    public static void main(String[] args) throws Exception {
        JdbcConnectionPool cp = JdbcConnectionPool.create(
            "jdbc:h2:~/test", "sa", "sa");
        for (int i = 0; i < args.length; i++) {
            Connection conn = cp.getConnection();
            conn.createStatement().execute(args[i]);
            conn.close();
        }
        cp.dispose();
    }
}

全文检索

H2 包含了两种全文检索的实现。一种通过使用 Apache Lucene 来实现,另一种是通过存储索引文件到数据库里的一张特殊表来实现的(私有实现)。

使用私有全文检索

通过下面的调用来实现初始化:

CREATE ALIAS IF NOT EXISTS FT_INIT FOR "org.h2.fulltext.FullText.init";
CALL FT_INIT();

如果你要用到私有全文检索,你需要在每个数据库里都初始化它。然后你能创建一张表用于全文检索的索引,如:

CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR);
INSERT INTO TEST VALUES(1, 'Hello World');
CALL FT_CREATE_INDEX('PUBLIC', 'TEST', NULL);

PUBLIC 是 schema 的名字, TEST 是索引表名。字段名列表是可选的,在上面的例子中,所有的字段都被索引,索引的更新是实时的,使用下面的查询语句可以进行搜索:

SELECT * FROM FT_SEARCH('Hello', 0, 0);

下面的语句将得到一个指定内容的搜索结果集。

QUERY: "PUBLIC"."TEST" WHERE "ID"=1

删除表上的索引

CALL FT_DROP_INDEX('PUBLIC', 'TEST');

要得到原始的数据,需要使用 FT_SEARCH_DATA('Hello', 0, 0);。结果包含字段 SCHEMA (schema名), TABLE (表名), COLUMNS (字段名数组), 和 KEYS (对象数组)。可以和表做连接,使用连接如下:SELECT T.* FROM FT_SEARCH_DATA('Hello', 0, 0) FT, TEST T WHERE FT.TABLE='TEST' AND T.ID=FT.KEYS[0];

你也能在 Java 应用中使用索引:

org.h2.fulltext.FullText.search(conn, text, limit, offset);
org.h2.fulltext.FullText.searchData(conn, text, limit, offset);

用 Lucene 实现的全文检索

使用 Lucene 实现的全文检索,你需要将 Lucene 加入到 classpath 中,并且处理相关的依赖,如果你使用 H2 控制台,你能增加 Lucene 的 jar 文件到环境变量 H2DRIVERSCLASSPATH 中。通过下面的语句初始化 Lucene 全文检索:

CREATE ALIAS IF NOT EXISTS FTL_INIT FOR "org.h2.fulltext.FullTextLucene.init";
CALL FTL_INIT();

如果你需要是使用 Lucene 全文检索,你每个数据库都需要初始化。你也能通过下面的语句创建全文索引表:

CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR);
INSERT INTO TEST VALUES(1, 'Hello World');
CALL FTL_CREATE_INDEX('PUBLIC', 'TEST', NULL);

PUBLIC 是 schema 名, TEST 是表名. 字段名列表是可选的,在上面的例子中,所有的字段都被索引,索引的更新是实时的,使用下面的查询语句可以进行搜索:

SELECT * FROM FTL_SEARCH('Hello', 0, 0);

下面的语句将得到一个指定内容的搜索结果集:

QUERY: "PUBLIC"."TEST" WHERE "ID"=1

表上的索引(警告称,这将对所有的整个数据库的全文索引进行检索):

CALL FTL_DROP_INDEX('PUBLIC', 'TEST');

要得到原始的数据,需要使用 FTL_SEARCH_DATA('Hello', 0, 0);。结果包含字段 SCHEMA (schema名), TABLE (表名), COLUMNS (字段名数组), 和KEYS (对象数组)。可以和表做连接,使用连接如下SELECT T.* FROM FTL_SEARCH_DATA('Hello', 0, 0) FT, TEST T WHERE FT.TABLE='TEST' AND T.ID=FT.KEYS[0];

你也能在JAVA应用中使用索引:

org.h2.fulltext.FullTextLucene.search(conn, text, limit, offset);
org.h2.fulltext.FullTextLucene.searchData(conn, text, limit, offset);

Lucene 搜索支持全文搜索仅在特定的列。列名必须大写(如果原始列双援引除外)。为列名下划线(_),另一个强调需要添加。例子:

CREATE ALIAS IF NOT EXISTS FTL_INIT FOR "org.h2.fulltext.FullTextLucene.init";
CALL FTL_INIT();
DROP TABLE IF EXISTS TEST;
CREATE TABLE TEST(ID INT PRIMARY KEY, FIRST_NAME VARCHAR, LAST_NAME VARCHAR);
CALL FTL_CREATE_INDEX('PUBLIC', 'TEST', NULL);
INSERT INTO TEST VALUES(1, 'John', 'Wayne');
INSERT INTO TEST VALUES(2, 'Elton', 'John');
SELECT * FROM FTL_SEARCH_DATA('John', 0, 0);
SELECT * FROM FTL_SEARCH_DATA('LAST_NAME:John', 0, 0);
CALL FTL_DROP_ALL();

Lucene 全文搜索实现内部并不是同步的。如果你同时更新数据库和查询全文搜索(直接使用 Java API 的 H2 或 Lucene 本身),您需要确保操作正确同步。如果不是这样的话,你可能会有异常 org.apache.lucene.store.AlreadyClosedException: this IndexReader is closed