混合模式是嵌入式模式和服务器模式的组合。第一个连接到数据库的应用程序在嵌入式模式下进行连接,但同时也会启动服务器,以便其他应用程序(在不同进程或虚拟机中运行)可以同时访问相同的数据。本地连接的速度与仅在嵌入式模式下使用数据库一样快,而远程连接则稍慢一些。
服务器可以在应用程序内启动和停止(使用服务器 API),也可以自动启动和停止(自动混合模式)。使用自动混合模式时,所有要连接数据库的客户端(不管是本地连接还是远程连接)都可以使用完全相同的数据库 URL 进行连接。
多个进程可以访问同一个数据库,而无需手动启动服务器。为此,请在数据库 URL 中添加 ;AUTO_SERVER=TRUE。无论数据库是否已打开,都可以使用相同的数据库 URL。此功能不适用于内存数据库。数据库 URL 示例:
jdbc:h2:/data/test;AUTO_SERVER=TRUE
对该数据库的所有连接使用相同的 URL。在内部,使用该模式时,与数据库的首次连接将在嵌入式模式下进行,此外还将在内部启动服务器(作为守护进程线程)。如果数据库已在另一个进程中打开,则会自动使用服务器模式。服务器的 IP 地址和端口存储在 .lock.db 文件中,因此无法支持内存数据库。
打开第一个数据库连接的应用程序使用嵌入式模式,该模式比服务器模式更快。因此,如果可能,主程序应首先打开数据库。第一个连接会自动启动一个随机端口上的服务器。该服务器允许远程连接,但只能连接到该数据库(为确保这一点,客户端会读取 .lock.db 文件,并将其中存储的随机密钥发送到服务器)。当第一个连接关闭时,服务器就会停止。如果其他(远程)连接仍处于打开状态,其中一个连接将启动服务器(自动重连功能已自动启用)。
所有进程都需要访问数据库文件。如果关闭第一个连接(启动服务器的连接),其他连接的未结事务将回滚(如果不禁用自动提交,这可能不是问题)。不支持显式客户端/服务器连接(使用 jdbc:h2:tcp:// 或 ssl://)。内存数据库不支持该模式。
下面举例说明如何使用这种模式。应用程序 1 和 2 不一定在同一台计算机上启动,但它们需要访问数据库文件。应用程序 1 和 2 通常是两个不同的进程(但也可以在同一进程中运行)。
// Application 1: DriverManager.getConnection("jdbc:h2:/data/test;AUTO_SERVER=TRUE"); // Application 2: DriverManager.getConnection("jdbc:h2:/data/test;AUTO_SERVER=TRUE");
使用此功能时,服务器默认使用任何空闲的 TCP 端口。可以使用 AUTO_SERVER_PORT=9090 手动设置端口。
在开发过程中,开发人员可以在本地使用嵌入式模式的连接方式快速进行开发和测试,而测试人员或其他相关人员可以通过远程连接方式访问数据库进行集成测试或查看数据状态等操作。
对于一些小型企业应用,既希望在本地有一个简单高效的数据库访问方式,又需要为少数远程客户端(如远程办公的员工或其他部门的特定需求)提供数据库服务时,H2 混合模式是一个不错的选择。它可以减少数据库部署和管理的复杂性,同时满足多种访问需求。
在一台机器上面启动两个 Java 进程,一个进程不断的向表中写入数据,另一个进程则从该数据表中查询数据。
负责创建 users 表,和不断的向 users 表写入数据,例如:
package com.hxstrive.h2.mixed_database; import java.sql.*; /** * H2嵌入式数据库的示例代码-使用AUTO_SERVER模式,写入数据 * @author hxstrive.com * @since 1.0.0 2024/9/20 11:38 */ public class H2MixedDatabaseExample1 { public static void main(String[] args) throws Exception { try { // 创建连接,这里假设数据库文件存储在当前目录下名为test.db Connection connection = DriverManager.getConnection("jdbc:h2:~/test;AUTO_SERVER=TRUE;AUTO_SERVER_PORT=9090"); Statement statement = connection.createStatement(); // 创建一个名为users的表,包含id和name两列 statement.execute("CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255))"); // 插入一条数据到users表 for(int i = 1; i < 1000; i++) { statement.execute("INSERT INTO users (id, name) VALUES (" + i + ", 'John')"); System.out.println("写入数据完成...id=" + i); Thread.sleep(1000); } // 关闭资源 statement.close(); connection.close(); } catch (SQLException e) { e.printStackTrace(); } } }
运行示例,输出如下:
写入数据完成...id=1 写入数据完成...id=2 写入数据完成...id=3 写入数据完成...id=4 写入数据完成...id=5 ...
负责不断的从 users 表中读取数据,例如:
package com.hxstrive.h2.mixed_database; import java.sql.*; /** * H2嵌入式数据库的示例代码,使用H2 Server数据库,查询数据 * @author hxstrive.com * @since 1.0.0 2024/9/20 11:38 */ public class H2MixedDatabaseExample2 { public static void main(String[] args) throws Exception { try { // 连接到H2 Server数据库 Connection connection = DriverManager.getConnection("jdbc:h2:~/test;AUTO_SERVER=TRUE;AUTO_SERVER_PORT=9090"); // 查询users表中的数据 Statement statement = connection.createStatement(); while(true) { ResultSet resultSet = statement.executeQuery("SELECT * FROM users"); while (resultSet.next()) { int id = resultSet.getInt("id"); String name = resultSet.getString("name"); System.out.println("id: " + id + ", name: " + name); } resultSet.close(); Thread.sleep(1000); } } catch (SQLException e) { e.printStackTrace(); } } }
运行示例,输出如下:
id: 1, name: John id: 1, name: John id: 2, name: John id: 1, name: John id: 2, name: John id: 3, name: John ...