1. 概要

このクイックチュートリアルでは、複数のSpring Bootアプリケーションから同じインメモリH2データベースにアクセスする方法を示します。

これを行うために、2つの異なるSpring Bootアプリケーションを作成します。 最初のSpringBootアプリケーションはメモリ内のH2インスタンスを開始しますが、2番目のアプリケーションはTCPを介して最初のアプリケーションの埋め込みH2インスタンスにアクセスします。

2. バックグラウンド

ご存知のように、インメモリデータベースはより高速で、アプリケーション内の埋め込みモードで使用されることがよくあります。 ただし、インメモリデータベースは、サーバーの再起動後もデータを保持しません。

その他の背景については、最も一般的に使用されるインメモリデータベースおよび自動テストでのインメモリデータベースの使用に関する記事を確認してください。

3. Mavenの依存関係

この記事の2つのSpringBootアプリケーションには、同じ依存関係が必要です。

<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データソースの設定

まず、最も重要なコンポーネント(インメモリH2データベースのSpring bean)を定義し、TCPポートを介して公開しましょう。

@Bean(initMethod = "start", destroyMethod = "stop")
public Server inMemoryH2DatabaseaServer() throws SQLException {
    return Server.createTcpServer(
      "-tcp", "-tcpAllowOthers", "-tcpPort", "9090");
}

initMethodおよびdestroyMethodパラメーターで定義されたメソッドは、H2データベースを開始および停止するためにSpringによって呼び出されます。

-tcp パラメーターは、TCPサーバーを使用してH2を起動するようにH2に指示します。 createTcpServerメソッドの3番目と4番目のパラメーターで使用するTCPポートを指定します。

パラメータtcpAllowOthersは、同じホストまたはリモートホストで実行されている外部アプリケーションからのアクセスのためにH2を開きます。

次に、 application.properties ファイルにいくつかのプロパティを追加して、Spring Bootの自動構成機能によって作成されたデフォルトのデータソースオーバーライドしましょう。

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. 最初のSpringBootアプリケーションのブートストラップ

次に、Spring Bootアプリケーションをブートストラップするために、 @ SpringBootApplicationアノテーションを使用してクラスを作成します。

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

すべてが正しく配線されていることをテストするために、コードを追加してテストデータを作成しましょう。

initDb という名前のメソッドを定義し、 @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);
    });

    // Query test data and print results
}

6. 2番目のSpringBootアプリケーション

次に、上記で定義したものと同じMaven依存関係を必要とするクライアントアプリケーションのコンポーネントを見てみましょう。

まず、データソースのプロパティを上書きします。 JDBC URLのポート番号が、H2が最初のアプリケーションで着信接続をリッスンしているポート番号と同じであることを確認する必要があります。

クライアントアプリケーションのapplication.propertiesファイルは次のとおりです。

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

最後に、クライアントのSpringBootアプリケーションのメインクラスを作成します。

ここでも簡単にするために、@PostConstructアノテーションを使用してinitDbメソッドを含む@SpringBootApplicationを定義します。

@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);
        });

        // Fetch data using SELECT statement and print results
    } 
}

7. サンプル出力

これで、両方のアプリケーションを1つずつ実行すると、コンソールログをチェックして、2番目のアプリケーションが期待どおりにデータを出力することを確認できます。

これが最初のSpringBootアプリケーションのコンソールログです:

****** 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

そして、これが2番目のSpringBootアプリケーションのコンソールログです:

****** 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. 結論

この簡単な記事では、複数のSpringBootアプリケーションから同じインメモリH2データベースインスタンスにアクセスする方法を説明しました。

いつものように、実用的なコード例はGitHub利用できます。