基本 ローカル(Spring Boot) 約35分

DB とつないで CRUD の基本を作る

H2 Database と Spring Data JPA を導入し、@Entity・JpaRepository で ArrayList を置き換える。

前回までに REST API で GET / POST / PUT / DELETE を実装しました。ただしデータは ArrayList に入れていたため、アプリを再起動するとすべて消えます。今回はデータベースを接続して、データを永続的に保存します。

H2 Database を使う

データベースには H2 Database を使います。H2 は Java に組み込めるデータベースで、追加のインストールが不要です。Spring Boot のプロジェクトに依存を追加するだけで使えます。

DB コースでは DB Browser for SQLite を使いましたが、Spring Boot では H2 が標準的な開発用 DB です。SQL の書き方はほぼ同じです。

依存を追加する

pom.xml<dependencies> セクションに、次の2つを追加します。

<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-h2console</artifactId>
</dependency>
  • spring-boot-starter-data-jpa — Java からデータベースを操作する仕組み(JPA)を使うためのライブラリ
  • h2 — 組み込み型のデータベース
  • spring-boot-h2console — ブラウザから H2 を操作するコンソール機能。Spring Boot 4 からオートコンフィグが独立モジュールに分離されたため、個別に追加が必要

pom.xml は「このプロジェクトが使うライブラリの一覧」を管理するファイルです。ここに書いておけば、Maven が自動でダウンロードしてくれます。

application.properties を設定する

src/main/resources/application.properties を開き、次の設定を追加します。

spring.datasource.url=jdbc:h2:mem:demo
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.hibernate.ddl-auto=create-drop
spring.h2.console.enabled=true
設定意味
spring.datasource.urlデータベースの接続先。mem:demo はメモリ上にDBを作る設定
spring.jpa.hibernate.ddl-auto=create-dropアプリ起動時にテーブルを自動作成し、停止時に削除する
spring.h2.console.enabled=trueブラウザで SQL を直接実行できる H2 コンソールを有効にする

mem:demo はメモリDBなので、アプリ停止でデータは消えます。開発の段階ではこの方が都合がよく、テーブル構造を変えるたびに手動で DROP する必要がありません。

Employee を @Entity にする

DB コースで「テーブル = Java のクラス」と対比しました。Spring Data JPA ではまさにそのとおりで、Java のクラスをそのままデータベースのテーブルとして扱います。

Employee.java を次のように書き換えます。

package com.example.demo;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private String department;

    public Employee() {
    }

    public Employee(String name, String department) {
        this.name = name;
        this.department = department;
    }

    public Integer getId() { return id; }
    public String getName() { return name; }
    public String getDepartment() { return department; }

    public void setId(Integer id) { this.id = id; }
    public void setName(String name) { this.name = name; }
    public void setDepartment(String department) { this.department = department; }
}

追加されたアノテーションの意味です。

アノテーション役割
@Entity「このクラスはデータベースのテーブルに対応する」と宣言
@Idこのフィールドがテーブルの主キー(PRIMARY KEY)になる
@GeneratedValueID を自動で採番する(SQL の INTEGER PRIMARY KEY と同じ役割)

SQL の回で書いた CREATE TABLE employees (id INTEGER PRIMARY KEY, name TEXT, department TEXT) と同じテーブルが、アノテーションによって自動で作られます。

コンストラクタから id 引数を外しました。ID はデータベースが自動で振るため、コードから指定する必要がなくなります。

Repository を作る

データベースへの CRUD 操作を担当するインターフェースを作ります。src/main/java/com/example/demo/EmployeeRepository.java を作成します。

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;

public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
}

これだけです。JpaRepository<Employee, Integer> を継承すると、次のメソッドが自動で使えるようになります。

メソッドSQL での対応
findAll()SELECT * FROM employees
findById(id)SELECT * FROM employees WHERE id = ?
save(employee)INSERT または UPDATE(ID の有無で自動判定)
deleteById(id)DELETE FROM employees WHERE id = ?

SQL を1行も書かずに CRUD ができます。SQL の回で手書きした INSERT や SELECT を、Spring Data JPA が内部で自動生成しています。

コントローラを書き換える

ArrayList を使っていた EmployeeController.java を、Repository を使う形に書き換えます。

package com.example.demo;

import java.util.List;
import org.springframework.web.bind.annotation.*;

@RestController
@CrossOrigin
public class EmployeeController {

    private final EmployeeRepository repository;

    public EmployeeController(EmployeeRepository repository) {
        this.repository = repository;
    }

    @GetMapping("/api/employees")
    public List<Employee> getAll() {
        return repository.findAll();
    }

    @GetMapping("/api/employees/{id}")
    public Employee getOne(@PathVariable Integer id) {
        return repository.findById(id).orElse(null);
    }

    @PostMapping("/api/employees")
    public Employee create(@RequestBody Employee employee) {
        return repository.save(employee);
    }

    @PutMapping("/api/employees/{id}")
    public Employee update(@PathVariable Integer id, @RequestBody Employee employee) {
        employee.setId(id);
        return repository.save(employee);
    }

    @DeleteMapping("/api/employees/{id}")
    public String delete(@PathVariable Integer id) {
        repository.deleteById(id);
        return "deleted";
    }
}

変更点を整理します。

  • ArrayListnextId がなくなり、EmployeeRepository に置き換わった
  • コンストラクタで repository を受け取る(Spring Boot が自動で渡してくれる。これを依存性注入と呼ぶ)
  • getOne@PathVariable を追加し、ID で1件取得できるようになった
  • save メソッドは ID がなければ INSERT、あれば UPDATE として動く

初期データを入れる

アプリ起動時にテストデータを入れておくと確認しやすくなります。DemoApplication.java を次のように更新します。

package com.example.demo;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class DemoApplication {

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

    @Bean
    CommandLineRunner initData(EmployeeRepository repository) {
        return args -> {
            repository.save(new Employee("田中太郎", "開発部"));
            repository.save(new Employee("鈴木花子", "営業部"));
            repository.save(new Employee("佐藤次郎", "開発部"));
        };
    }
}

CommandLineRunner はアプリ起動後に1回だけ実行される処理です。3件のデータが自動で INSERT されます。

H2 コンソールで確認する

アプリを起動したら、ブラウザで http://localhost:8080/h2-console を開きます。

ログイン画面が表示されるので、次のように入力します。

項目
JDBC URLjdbc:h2:mem:demo
User Namesa
Password(空欄のまま)
H2 コンソールのログイン画面

「Connect」を押すとSQL を実行できる画面が開きます。

SELECT * FROM EMPLOYEE;

DB コースで練習した SQL がそのまま使えます。Spring Boot が裏で作ったテーブルの中身を直接確認できるため、API とデータベースの両方から動作を検証できます。

H2 コンソールでクエリを実行した結果

動作確認のポイント

  • http://localhost:8080/api/employees で初期データ3件のJSON が返るか
  • curl で POST → GET して、データが増えているか
  • H2 コンソールで SELECT * FROM EMPLOYEE を実行し、同じデータが見えるか
  • アプリを再起動しても初期データ3件で再開されるか(create-drop のため)

ここまでの整理

要素役割
H2 Database組み込みデータベース。追加インストール不要
@Entityクラスをテーブルに対応させる
@Id + @GeneratedValue主キーの自動採番
JpaRepositoryCRUD メソッドの自動生成
H2 コンソールブラウザから SQL を実行して確認

次回は最後の仕上げとして、fetch で API を呼び出す一覧画面を作り、ブラウザからデータの閲覧・追加・削除ができる CRUD 画面を完成させます。