前回までに 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)になる |
@GeneratedValue | ID を自動で採番する(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";
}
}
変更点を整理します。
ArrayListとnextIdがなくなり、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 URL | jdbc:h2:mem:demo |
| User Name | sa |
| Password | (空欄のまま) |
「Connect」を押すとSQL を実行できる画面が開きます。
SELECT * FROM EMPLOYEE;
DB コースで練習した SQL がそのまま使えます。Spring Boot が裏で作ったテーブルの中身を直接確認できるため、API とデータベースの両方から動作を検証できます。
動作確認のポイント
http://localhost:8080/api/employeesで初期データ3件のJSON が返るか- curl で POST → GET して、データが増えているか
- H2 コンソールで
SELECT * FROM EMPLOYEEを実行し、同じデータが見えるか - アプリを再起動しても初期データ3件で再開されるか(
create-dropのため)
ここまでの整理
| 要素 | 役割 |
|---|---|
| H2 Database | 組み込みデータベース。追加インストール不要 |
@Entity | クラスをテーブルに対応させる |
@Id + @GeneratedValue | 主キーの自動採番 |
JpaRepository | CRUD メソッドの自動生成 |
| H2 コンソール | ブラウザから SQL を実行して確認 |
次回は最後の仕上げとして、fetch で API を呼び出す一覧画面を作り、ブラウザからデータの閲覧・追加・削除ができる CRUD 画面を完成させます。