1. 概述

在本教程中,我们将演示如何让多个 Spring Boot 应用共享同一个内存 H2 数据库实例

实现思路是:创建两个独立的 Spring Boot 应用,第一个应用启动一个内存 H2 实例,并通过 TCP 暴露出来;第二个应用则通过 TCP 连接到第一个应用所暴露的 H2 实例。

2. 背景知识

我们知道,内存数据库速度快,通常以嵌入模式运行在应用内部。但它的缺点也很明显 —— 重启后数据不会保留

如果你对内存数据库感兴趣,可以参考我们之前的文章:

3. Maven 依赖配置

两个 Spring Boot 应用所需的依赖完全一致:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
</dependencies>

4. 配置 H2 数据源

首先,我们要定义一个关键组件 —— 一个可暴露为 TCP 服务的 H2 内存数据库 Bean:

@Bean(initMethod = "start", destroyMethod = "stop")
public Server inMemoryH2DatabaseaServer() throws SQLException {
    return Server.createTcpServer(
      "-tcp", "-tcpAllowOthers", "-tcpPort", "9090");
}
  • initMethod = "start"destroyMethod = "stop" 是告诉 Spring 在容器启动和关闭时自动调用 H2 Server 的开启和关闭方法。
  • -tcp 表示启用 TCP 服务器。
  • -tcpAllowOthers 允许其他主机访问这个数据库(⚠️注意安全问题)。
  • -tcpPort 9090 设置监听端口为 9090。

接下来,在 application.properties 文件中覆盖默认的数据源配置:

spring.datasource.url=jdbc:h2:mem:mydb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create

重点提示:这些配置项在所有需要连接该 H2 实例的应用中必须保持一致!

5. 启动第一个 Spring Boot 应用

我们创建一个主类并加上 @SpringBootApplication 注解:

@SpringBootApplication
public class SpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApp.class, args);
    }
}

为了验证数据库是否正常工作,我们添加一些初始化数据逻辑。使用 @PostConstruct 标记的方法会在 Spring 初始化完成后自动执行:

@PostConstruct
private void initDb() {
    String sqlStatements[] = {
      "drop table employees if exists",
      "create table employees(id serial,first_name varchar(255),last_name varchar(255))",
      "insert into employees(first_name, last_name) values('Eugen','Paraschiv')",
      "insert into employees(first_name, last_name) values('Scott','Tiger')"
    };

    Arrays.asList(sqlStatements).forEach(sql -> {
        jdbcTemplate.execute(sql);
    });

    // 查询并打印结果
}

6. 第二个 Spring Boot 客户端应用

第二个应用也需要相同的 Maven 依赖。

关键在于修改数据源配置,确保 JDBC URL 中的端口号与第一个应用中设置的 TCP 端口一致:

spring.datasource.url=jdbc:h2:tcp://localhost:9090/mem:mydb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create

然后创建客户端主类:

@SpringBootApplication
public class ClientSpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(ClientSpringBootApp.class, args);
    }
    
    @PostConstruct
    private void initDb() {
        String sqlStatements[] = {
          "insert into employees(first_name, last_name) values('Donald','Trump')",
          "insert into employees(first_name, last_name) values('Barack','Obama')"
        };

        Arrays.asList(sqlStatements).forEach(sql -> {
            jdbcTemplate.execute(sql);
        });

        // 使用 SELECT 查询并打印结果
    } 
}

7. 示例输出

分别运行两个应用后,我们可以看到控制台日志如下:

第一个应用输出:

****** Creating table: Employees, and Inserting test data ******
drop table employees if exists
create table employees(id serial,first_name varchar(255),last_name varchar(255))
insert into employees(first_name, last_name) values('Eugen','Paraschiv')
insert into employees(first_name, last_name) values('Scott','Tiger')
****** Fetching from table: Employees ******
id:1,first_name:Eugen,last_name:Paraschiv
id:2,first_name:Scott,last_name:Tiger

第二个应用输出:

****** Inserting more test data in the table: Employees ******
insert into employees(first_name, last_name) values('Donald','Trump')
insert into employees(first_name, last_name) values('Barack','Obama')
****** Fetching from table: Employees ******
id:1,first_name:Eugen,last_name:Paraschiv
id:2,first_name:Scott,last_name:Tiger
id:3,first_name:Donald,last_name:Trump
id:4,first_name:Barack,last_name:Obama

可以看到,第二个应用不仅能访问到第一个应用插入的数据,还能继续插入自己的数据。

8. 总结

在这篇文章中,我们展示了如何通过 TCP 方式让多个 Spring Boot 应用共享同一个内存 H2 数据库实例

这种方式适用于开发阶段快速验证多应用间的数据交互,或者用于构建集成测试环境。

踩坑提醒

  • 确保两个应用使用的数据库名称、用户名、密码一致;
  • 注意防火墙和权限设置,避免外部非法访问;
  • 生产环境慎用,仅限本地调试或测试环境使用。

完整代码示例可在 GitHub 获取。


原始标题:Access the Same In-Memory H2 Database in Multiple Spring Boot Applications