H2 连接到内存数据库

内存数据库(In-Memory Database,简称IMDB)是一种将数据主要存储在计算机的主存(RAM)中,而不是存储在磁盘上的数据库系统。

对于某些场景,例如:快速原型开发、测试、高性能操作、只读数据库,可能不需要持久化数据或持久化对数据的更改,此时使用内存数据库较为合适。

H2 数据库支持内存模式,即不持久化数据。要开启内存数据库模式是通过在 JDBC URL 地址设置关键信息来实现,格式如下:

// 连接到默认名称的内存数据库
jdbc:h2:mem:

// 连接到名为 databaseName 的内存数据库
jdbc:h2:mem:<databaseName>

示例:

jdbc:h2:mem:test_mem

上面地址将连接到名为 test_mem 的内存数据库。

注意事项:

(1)在某些情况下,只需要与内存数据库建立一个连接。这意味着要打开的数据库是私有的。在这种情况下,可以使用默认名称的内存数据库,数据库的 URL 为 jdbc:h2:mem:。如果在同一虚拟机中打开两个连接,意味着打开两个不同的(私有)数据库。例如:

// 创建连接
Connection connection1 = DriverManager.getConnection("jdbc:h2:mem:");
Statement statement1 = connection1.createStatement();
statement1.execute("CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255))");
statement1.executeQuery("SELECT * FROM users");

// org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USERS" not found (this database is empty); SQL statement
Connection connection2 = DriverManager.getConnection("jdbc:h2:mem:");
Statement statement2 = connection2.createStatement();
statement2.executeQuery("SELECT * FROM users");

(2)有时需要多个连接,连接到同一个内存数据库。在这种情况下,数据库 URL 必须包含名称。例如:jdbc:h2:mem:db1。注意:使用此 URL 访问同一数据库只能在同一虚拟机和类加载器环境中进行。

(3)要从其他进程或其他计算机访问内存数据库,需要在创建内存数据库的同一进程中启动 TCP 服务器。然后,其他进程需要通过 TCP/IP 或 TLS 访问数据库,如:jdbc:h2:tcp://localhost/mem:db1。例如:

// 进程1:创建内存数据库,且启动服务
Connection connection = DriverManager.getConnection("jdbc:h2:mem:test-db");
Statement statement = connection.createStatement();
statement.execute("CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255))");
statement.execute("INSERT INTO users VALUES (1, '张三')");
// 查询结果
ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
while (resultSet.next()) {
    System.out.println(resultSet.getInt("id") + " - " + resultSet.getString("name"));
}
// 启动H2服务,让其他进程远程连接该内存数据库
Server.createTcpServer("-tcp","-web","-ifNotExists").start();

// 进程2:远程访问内存数据库
Connection connection = DriverManager.getConnection("jdbc:h2:tcp://localhost/mem:test-db");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
while (resultSet.next()) {
    System.out.println(resultSet.getInt("id") + " - " + resultSet.getString("name"));
}

(4)默认情况下,关闭数据库的最后一个连接,H2 会关闭数据库。对于内存数据库,这意味着内容丢失。要保持数据库不被关闭,可在数据库 URL 中添加 ;DB_CLOSE_DELAY=-1。例如: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1。注意:这可能会造成内存泄漏,需要删除数据库时,请使用 SHUTDOWN 命令。例如:

不使用 DB_CLOSE_DELAY 的效果:

// 创建连接
{
    Connection connection = DriverManager.getConnection("jdbc:h2:mem:test-db");
    Statement statement = connection.createStatement();
    statement.execute("CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255))");
    statement.execute("INSERT INTO users VALUES (1, '张三')");
    statement.close();
    connection.close(); // 关闭连接,此时数据库内存中的数据会被清空
}

// 重新打开连接
{
    Connection connection = DriverManager.getConnection("jdbc:h2:mem:test-db");
    Statement statement = connection.createStatement();
    // 报错:因为数据库内存中的数据被清空了,所以找不到表
    // org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USERS" not found (this database is empty); SQL statement:
    ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
    while (resultSet.next()) {
        System.out.println(resultSet.getInt("id") + " - " + resultSet.getString("name"));
    }
}

使用 DB_CLOSE_DELAY 的效果:

// 创建连
{
    Connection connection = DriverManager.getConnection("jdbc:h2:mem:test-db;DB_CLOSE_DELAY=-1");
    Statement statement = connection.createStatement();
    statement.execute("CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255))");
    statement.execute("INSERT INTO users VALUES (1, '张三')");
    statement.close();
    connection.close(); // 关闭连接,此时数据库内存中的数据不会被清空
}

// 重新打开连接
{
    Connection connection = DriverManager.getConnection("jdbc:h2:mem:test-db");
    Statement statement = connection.createStatement();
    ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
    while (resultSet.next()) {
        System.out.println(resultSet.getInt("id") + " - " + resultSet.getString("name"));
    }
    statement.execute("shutdown"); // 关闭数据库,此时内存中的数据会被清空
    statement.close();
    resultSet.close();
    connection.close(); // 关闭连接,此时数据库内存中的数据会被清空
}

// 再次打开连接
{
    Connection connection = DriverManager.getConnection("jdbc:h2:mem:test-db");
    Statement statement = connection.createStatement();
    // 报错:因为内存中的数据库被清理了
    // org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "USERS" not found (this database is empty); SQL statement:
    ResultSet resultSet = statement.executeQuery("SELECT * FROM users");
    while (resultSet.next()) {
        System.out.println(resultSet.getInt("id") + " - " + resultSet.getString("name"));
    }
    statement.close();
    resultSet.close();
    connection.close();
}


说说我的看法
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号