「まずはDB連携を体験したい」「MySQL を入れる前に動くところを確認したい」そんな時に最強の相棒が H2 Database(インメモリDB) です。今回は Spring Boot に H2 を組み込み、テーブル作成 → データ投入 → 取得/登録/更新/削除 までを最短ルートで体験します。初心者が迷いやすい設定ポイントも紹介しながら、一緒に進めていきましょう。
H2データベースとは何か
- インメモリ型のデータベースで、アプリケーションが起動している間だけデータが保持されます。アプリを停止するとデータは消えますが、逆に「試すだけ」「一時的な確認」といった場面にはとても便利です。
- インストール不要で、依存関係にH2を追加するだけですぐに利用可能。開発環境を汚さないのもメリットです。
- ブラウザから中身を直接見られるH2コンソールが付属しており、SQLを書いて確認する練習にも使えます。
- モード切替が豊富で、PostgreSQLやMySQLなど主要なRDBの方言をシミュレーションできます。これにより、本番用DBに近い挙動を試すことが可能です。
- 学習や動作確認に最適。DBをインストールできない環境や、チーム開発で素早く検証したいときに活用されています。
H2データベースの環境を整える
Spring Initializrからプロジェクトを作成する方法
- Spring Initializr にアクセス。
- Project: Gradle Project を選択。
- Language: Java。
- Spring Boot: 最新の安定版。
- Dependencies に以下を追加:
- Spring Web
- Spring Data JPA
- H2 Database
- 生成されたZipをダウンロードし、IntelliJやEclipseにインポートします。
Gradle依存関係にH2とJPAを追加
build.gradle に自動生成されていますが、最低限以下が入っていればOKです。
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.5'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
description = 'Demo project for Spring Boot'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
compileOnly("org.projectlombok:lombok:1.18.38")
annotationProcessor("org.projectlombok:lombok:1.18.38")
testCompileOnly("org.projectlombok:lombok:1.18.38")
testAnnotationProcessor("org.projectlombok:lombok:1.18.38")
}
tasks.named('test') {
useJUnitPlatform()
}
Mavenプロジェクトを選んだ場合は pom.xml に以下の依存関係を追加すれば同じ環境になります。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>application.yml の基本設定
src/main/resources/application.yml を作成し、H2を有効化します。
spring:
application:
name: demo
datasource:
url: jdbc:h2:mem:demo;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
defer-datasource-initialization: true
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
h2:
console:
enabled: true
path: /h2-console
application.ymlでの設定項目詳細
spring.datasource.url:jdbc:h2:mem:demo;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE- インメモリDBをdemoとして作成。PostgreSQLモードで動作。識別子を小文字化。アプリ動作中は保持し、終了時のみ削除。
spring.datasource.username: sa- H2のデフォルトユーザー。学習用なのでパスワードなしで利用可能。
spring.datasource.password: 空欄- 学習用途のため空で問題なし(実運用では設定推奨)。
spring.datasource.driver-class-name: org.h2.Driver- JDBCドライバクラス。自動解決されるが明示するとわかりやすい。
spring.jpa.hibernate.ddl-auto: update- スキーマを自動更新。学習用に便利。実務ではnoneやマイグレーションツールを使用。
spring.jpa.show-sql: true- 実行SQLをログに出力。学習・デバッグ向け。
spring.jpa.properties.hibernate.format_sql: true- ログ出力されるSQLを整形して見やすく表示。
spring.h2.console.enabled: true- H2コンソールを有効化。ブラウザでDB確認が可能。
spring.h2.console.path: /h2-console- H2コンソールへのアクセスパス。起動後に http://localhost:8080/h2-console で利用可能。
よくあるつまずき
- JDBC URLの不一致:コンソールのURLと
application.ymlのURLが一致していないと接続できません。- 大文字/小文字問題:H2はクォートの有無で識別子の扱いが変わります。
DATABASE_TO_LOWER=TRUEで揺れを吸収。- テーブルが見つからない:
@Entity/@Idの付け忘れ、またはddl-autoがnone/validateのままになっている可能性。発展メモ
- ファイルモードへ切替:データを保持したい場合は
jdbc:h2:file:~/demoのようにmem→fileへ。初学段階では不要。- 別RDB方言の試用:本番がMySQLなら
MODE=MySQLを試すと方言差の検証ができます。
data.sql を“後から”流す(おすすめ)
Spring Boot 2.5以降では、
data.sqlがHibernateより先に実行される仕様になりました。そのため、まだテーブルが作られる前にINSERTが走り、エラーになる場合があります。これを防ぐためには次の設定を追加します。spring: jpa: defer-datasource-initialization: trueこれにより、Hibernateでテーブル作成 → その後に
data.sqlを実行 という順序になります。これで初期データが正しく投入されます。
H2データベースを利用した最小構築手順
環境の構築ができたところで、実際にコードを書いてみましょう。今回はBookのレコードをH2データベースに登録・消去・検索を行なってみたいと思います。
Entityの構築
Entityは、Javaのクラスをデータベースの表(テーブル)と対応させるためのマッピングオブジェクトです。そのクラスのインスタンスは、そのテーブルの1行(レコード)を表します。つまり「本」を表す Book クラスを Entity にすると、book テーブルの各行(タイトルや著者の情報)を Java オブジェクトで扱えるようになります。実際にEntityクラスを構築してみます。
package com.example.demo;
import jakarta.persistence.*;
import lombok.*;
@Entity
@Table(name = "book")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
private String author;
}Repositoryインターフェースの作成
Repository はデータベースにアクセスするための窓口で、SQLを書かずに標準的なCRUD操作や検索を行える仕組みです。JpaRepositoryをextendしていきます。
package com.example.demo;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByTitleContainingIgnoreCase(String keyword);
}初期データ投入方法
Spring Boot では src/main/resources 配下に data.sql を置くと、アプリ起動時に自動的に読み込まれ実行されます。そのため INSERT 文を記述すれば起動時にデータが挿入されます。インメモリDBの場合はアプリを再起動するたびにテーブルが再作成されるため、毎回 data.sql の内容が流し込まれる点も学習に便利です。 src/main/resources/data.sql
INSERT INTO book (title, author) VALUES ('Spring入門', 'Taro');
INSERT INTO book (title, author) VALUES ('はじめてのH2', 'Hanako');H2コンソールの利用方法
data.sqlをプロジェクトに追加したらまずは動かしてみましょう。アプリを起動後下記のURLに飛ぶとH2コンソールの接続画面が表示されます。
http://localhost:8080/h2-console
下記の画像はH2コンソールの接続画面になります。

この画面が開いたらConnectを押すことでH2コンソールの画面が開きます。

H2コンソールでできること
H2データベースでは下記のことができます。色々触ってみてください。
- SQL文を入力して実行し、結果を表形式で確認できます。
- 左側にテーブル一覧が表示され、クリックで内容を確認できます。
- テーブル定義(カラム名や型)の確認も可能です。
- INSERT/UPDATE/DELETE などを直接実行してデータを操作できます。
- 学習用途であれば、GUI的にDBの状態を覗ける“簡易的な管理ツール”として活用できます。
Service層とController層の実装
実際にH2データベースと接続できたら、Service層とController層を実装してDBを更新していきます。本記事ではService層とController層に実装を分割していますが、ではなぜ分割する必要があるのでしょうか?それには下記のような理由があります。
ここでの役割分担(なぜ分けるの?)
- Service層:アプリの業務ロジックの中心。トランザクション境界(
@Transactionalの付与)、バリデーション、複数リポジトリの編成、外部APIとの連携、ドメインルールの実装などを担います。入出力形式(HTTP/DB)に依存しない純粋なロジックを置くのが理想です。 - Controller層:HTTPの入出力担当。URLへのマッピング、クエリ/パス/ボディの受け取り、DTO↔ドメインの変換、適切なHTTPステータスコードの返却、例外のハンドリング(
@ControllerAdvice連携)などを行います。ロジックは極力書かず、Serviceを呼び出す薄い層に保ちます。
詳しくは下記の記事でも紹介しています。
業務ロジックを搭載するService層の実装
まずは業務ロジックを搭載するService層を実装していきます。
package com.example.demo;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository repo;
/** 一覧取得 */
@Transactional(readOnly = true)
public List<Book> findAll() {
return repo.findAll();
}
/** IDで1件取得(見つからなければ null) */
@Transactional(readOnly = true)
public Book findById(Long id) {
return repo.findById(id).orElse(null);
}
/** タイトル部分一致検索 */
@Transactional(readOnly = true)
public List<Book> searchByTitle(String keyword) {
return repo.findByTitleContainingIgnoreCase(keyword);
}
/** 登録 */
@Transactional
public Book create(String title, String author) {
return repo.save(new Book(null, title, author));
}
/** 更新(存在しない場合は null) */
@Transactional
public Book update(Long id, String title, String author) {
Optional<Book> opt = repo.findById(id);
if (opt.isEmpty()) return null;
Book b = opt.get();
if (title != null && !title.isBlank()) b.setTitle(title);
if (author != null) b.setAuthor(author);
return repo.save(b);
}
/** 削除 */
@Transactional
public void delete(Long id) {
repo.deleteById(id);
}
}| メソッド | 役割 |
|---|---|
findAll() | 全ての本を一覧で取得する |
findById(Long id) | 指定IDの本を1件取得する(存在しなければ null) |
searchByTitle(String keyword) | タイトルに部分一致する本を検索する |
create(String title, String author) | 新しい本を登録する |
update(Long id, String title, String author) | 指定IDの本を更新する(存在しなければ null) |
delete(Long id) | 指定IDの本を削除するメソッド名 |
@Transactionalとは?Spring が データベース処理をまとめて管理する仕組み です。
- メソッド全体を「1つの処理のかたまり(トランザクション)」として実行する
- 成功すれば コミット(DBに反映)、失敗すれば ロールバック(処理をなかったことにする)
readOnly = trueを付けると 読み取り専用 になり、無駄な更新チェックを省けて効率的
リクエストを受け付けるController層の実装
続いてリクエストを受け付けて、Service層に渡すControllerのBookControllerを実装します。
package com.example.demo;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/books")
@RequiredArgsConstructor
public class BookController {
private final BookService service;
@GetMapping
public List<Book> list() { return service.findAll(); }
@GetMapping("/{id}")
public Book get(@PathVariable Long id) { return service.findById(id); }
@PostMapping
public Book create(@RequestBody Map<String, String> body) {
return service.create(body.get("title"), body.get("author"));
}
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id) { service.delete(id); }
}
REST APIでのCRUD動作確認
Controllerが実装できたら実際にリクエストを送ってみましょう。今回はcurlコマンドを使ってリクエストをしてみました。
# 全件取得
curl http://localhost:8080/api/books
# 登録
curl -X POST http://localhost:8080/api/books \
-H "Content-Type: application/json" \
-d '{"title":"Spring Boot実践", "author":"Satoshi"}'
# 取得
curl http://localhost:8080/api/books/1
# 削除
curl -X DELETE http://localhost:8080/api/books/1
実装に問題がなければCRUD処理ができるはずです。DBの中身をコンソールから確認しながらコマンド実行してみてください。
まとめ
今回の記事では、Spring Boot と H2 データベースを使い、インストール不要で軽量な開発環境を構築しました。H2 はインメモリ型のため再起動ごとにリセットされ、学習や試行錯誤に最適です。Repository はinterfaceだけでよく、Spring Data JPA が自動で実装を用意してくれるため、SQL を書かずに CRUD 操作が可能です。さらに H2 コンソールによるデータ確認や、data.sql を利用した初期データ投入の仕組みも学びました。これらは今後 MySQL などの本格的なDBに移行する際にも役立ちます。
次回は、この CRUD 処理にバリデーションや例外処理を加え、実務に近い堅牢なアプリケーション作成に進みます。






