カテゴリ: Spring 更新日: 2025/12/25

Spring Data JPA入門!findAll()やfindBy**()の使い方などデータベース操作の基礎を学ぶ

Spring のDB検索(Spring Data JPA)
Spring のDB検索(Spring Data JPA)

先生と生徒の会話形式で理解しよう

生徒

「Spring Data JPAって何ですか?」

先生

「Spring Data JPAは、JavaのSpring Frameworkでデータベースとやり取りを簡単にするためのライブラリです。データの取得や保存を簡単にしてくれますよ。」

生徒

「それは便利そうですね!設定方法とか、使い方の基本も知りたいです。」

先生

「では、基本的な設定から実際のコード例まで順を追って説明していきますね!」

1. Spring Data JPAとは?

1. Spring Data JPAとは?
1. Spring Data JPAとは?

Spring Data JPAは、データベースとのやり取りを簡単にするためのSpring Frameworkの一部です。通常、SQLを直接書く必要があるデータ操作を、簡単なメソッドの呼び出しだけで実行できるようにしてくれます。また、リポジトリインターフェースを用いることで、自動的にCRUD(Create, Read, Update, Delete)操作を提供してくれるため、データベース操作がとてもスムーズになります。

2. データベース接続情報の設定(application.properties)

2. データベース接続情報の設定(application.properties)
2. データベース接続情報の設定(application.properties)

Spring Bootプロジェクトでデータベースを使うには、src/main/resources/application.propertiesにデータベースの接続設定を書きます。例えば、MySQLデータベースに接続する場合は以下のように記述します。


spring.datasource.url=jdbc:mysql://localhost:3306/your_database
spring.datasource.username=root
spring.datasource.password=your_password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

これで、データベースとの接続が確立されます。spring.datasource.urlには、データベースのURLを指定し、usernamepasswordにはそれぞれのデータベース情報を入力します。spring.jpa.show-sql=trueは、実行されるSQLをログに表示する設定です。

3. schema.sqlとdata.sqlでDBデータ準備

3. schema.sqlとdata.sqlでDBデータ準備
3. schema.sqlとdata.sqlでDBデータ準備

データベースのテーブルを自動生成したり、初期データを投入したい場合は、schema.sqldata.sqlファイルを使用します。これらのファイルをsrc/main/resourcesに置くことで、Spring Bootがアプリケーション起動時に自動で読み込んでくれます。


-- schema.sql
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100)
);

-- data.sql
INSERT INTO users (username, email) VALUES ('john_doe', 'john@example.com');
INSERT INTO users (username, email) VALUES ('jane_doe', 'jane@example.com');

これで、usersというテーブルが作成され、指定したデータが初期投入されます。Spring Data JPAを使う準備が整いました。

4. findAllメソッドでデータを取得する

4. findAllメソッドでデータを取得する
4. findAllメソッドでデータを取得する

Spring Data JPAのリポジトリインターフェースを利用することで、findAllメソッドを使用してテーブル内の全データを取得することができます。リポジトリは、JpaRepositoryインターフェースを拡張して作成します。


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

public interface UserRepository extends JpaRepository<User, Integer> {
}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
}

ここでは、getAllUsersメソッドでfindAllを呼び出し、すべてのUserエンティティを取得しています。findAllを使うことで、データベース内のすべてのデータを簡単に取得できます。

5. findBy***で条件付きデータ取得

5. findBy***で条件付きデータ取得
5. findBy***で条件付きデータ取得

特定の条件に基づいてデータを取得したい場合、Spring Data JPAのメソッド名の規約に基づいて、findByを使うことができます。例えば、usernameに基づいてデータを取得するには、以下のようにリポジトリメソッドを定義します。


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

public interface UserRepository extends JpaRepository<User, Integer> {
    User findByUsername(String username);
}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User getUserByUsername(String username) {
        return userRepository.findByUsername(username);
    }
}

このコードでは、usernameが一致するユーザーを取得するfindByUsernameメソッドを定義しています。このようにfindByに続けてカラム名を付けるだけで、条件付きのデータ取得が簡単に実現できます。

6. ページングとソート:findAll(Pageable)/Sortで効率よく取り出す

6. ページングとソート:findAll(Pageable)/Sortで効率よく取り出す
6. ページングとソート:findAll(Pageable)/Sortで効率よく取り出す

大量データを一括取得するとメモリを圧迫します。PageableSortを使えば、ページ単位で取り出し順序も指定できます。findAll(Pageable)はすべてのエンティティを対象に、findBy***と組み合わせれば条件付きのページングができます。


// Repository: 条件付きページング検索を追加
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Integer> {
    Page<User> findByUsernameContaining(String keyword, Pageable pageable);
}

// Service: ページング+ソートの例
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserRepository userRepository;
    public UserService(UserRepository userRepository) { this.userRepository = userRepository; }

    // 全件ページング
    public Page<User> getUsers(int page, int size) {
        return userRepository.findAll(PageRequest.of(page, size, Sort.by("id").descending()));
    }

    // キーワード検索+ページング
    public Page<User> searchUsers(String keyword, int page, int size) {
        var pageable = PageRequest.of(page, size, Sort.by("username").ascending());
        return userRepository.findByUsernameContaining(keyword, pageable);
    }
}

Pageは総件数・総ページ数・現在ページなどのメタ情報も持つため、一覧画面のページネーション実装が簡単になります。

7. 派生クエリの表現力:And/Or/Containing/Between/In/OrderBy など

7. 派生クエリの表現力:And/Or/Containing/Between/In/OrderBy など
7. 派生クエリの表現力:And/Or/Containing/Between/In/OrderBy など

findByに続けてプロパティ名とキーワードを連結するだけで多彩な条件を表現できます。代表例を覚えておくと、SQLを書かずに実用的な検索ができます。


public interface UserRepository extends JpaRepository<User, Integer> {

    // 複合条件
    List<User> findByUsernameAndEmail(String username, String email);
    List<User> findByUsernameOrEmail(String username, String email);

    // 部分一致・大文字小文字無視
    List<User> findByUsernameContainingIgnoreCase(String keyword);

    // 範囲・集合・NULL判定
    List<User> findByIdBetween(Integer start, Integer end);
    List<User> findByIdIn(Collection<Integer> ids);
    List<User> findByEmailIsNull();

    // 件数制限・並び替え
    List<User> findTop5ByOrderByIdDesc();
    List<User> findByUsernameContainingOrderByIdAsc(String keyword);
}

基本は「プロパティ+演算子」。存在しないプロパティ名やスペルミスは起動時に検出されるため、早期にバグに気づけます。

8. 保存・更新・削除の基本:save()/saveAll()/deleteById() と Optional の扱い

8. 保存・更新・削除の基本:save()/saveAll()/deleteById() と Optional の扱い
8. 保存・更新・削除の基本:save()/saveAll()/deleteById() と Optional の扱い

永続化(保存・更新)はsave、一括はsaveAll、削除はdeleteById等を使います。読み取り時のfindByIdOptionalを返すため、存在しない場合のハンドリングを忘れないようにします。更新系はトランザクション境界(@Transactional)内で行うのが基本です。


import jakarta.persistence.EntityNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserWriteService {

    private final UserRepository userRepository;
    public UserWriteService(UserRepository userRepository) { this.userRepository = userRepository; }

    @Transactional
    public User createUser(String username, String email) {
        User u = new User();
        u.setUsername(username);
        u.setEmail(email);
        return userRepository.save(u); // 新規保存
    }

    @Transactional
    public User updateEmail(int id, String newEmail) {
        User u = userRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("User not found: " + id));
        u.setEmail(newEmail);
        return userRepository.save(u); // 変更検知でもOK
    }

    @Transactional
    public void deleteUser(int id) {
        userRepository.deleteById(id);
    }
}

参照だけ欲しい場合は遅延ロードのgetReferenceById(id)も利用できます(存在チェックは実体アクセス時)。

9. 複雑な検索は @Query(JPQL/Native)で柔軟に記述する

9. 複雑な検索は @Query(JPQL/Native)で柔軟に記述する
9. 複雑な検索は @Query(JPQL/Native)で柔軟に記述する

派生クエリで表現しづらい条件は@Queryを使います。JPQLはエンティティ名・プロパティ名で書く抽象化されたクエリ、nativeQuery=trueで生SQLも実行できます。ページングと併用も可能です。


import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface UserRepository extends JpaRepository<User, Integer> {

    // JPQL:ユーザー名またはメールの部分一致(ページング対応)
    @Query("SELECT u FROM User u " +
           "WHERE LOWER(u.username) LIKE LOWER(CONCAT('%', :kw, '%')) " +
           "   OR LOWER(u.email)    LIKE LOWER(CONCAT('%', :kw, '%'))")
    Page<User> searchByKeyword(@Param("kw") String keyword, Pageable pageable);

    // ネイティブSQL:メールドメインで検索
    @Query(value = "SELECT * FROM users WHERE email LIKE CONCAT('%', :domain)",
           nativeQuery = true)
    List<User> findByEmailDomain(@Param("domain") String domain);
}

更新系のカスタムSQLを使う場合は@Modifying@Transactionalを併用します(書き込みであることを明示)。

まとめ

まとめ
まとめ

この記事では、Spring Data JPAを使用したデータベース操作について詳しく解説しました。初心者の方でもデータベース操作を簡単に行えるようになる基本的な内容から、実際のコーディング例までを網羅しています。特に、Spring Data JPAのリポジトリを利用することで、CRUD操作(Create, Read, Update, Delete)を簡単に実装できる点に注目しました。

また、データベース接続設定の方法やapplication.propertiesを使用した設定、schema.sqldata.sqlを使った初期データの準備についても詳しく解説しました。これにより、実際のアプリケーション開発に必要な準備が整います。

特に、findAllメソッドを使った全件取得や、findBy***を利用した条件付きデータ取得は、データベース操作の基本でありながら非常に強力です。これらを活用することで、SQLを直接記述することなく、効率的にデータを操作できます。

以下に、この記事で紹介したSpring Data JPAの基本的なコードをまとめます。これを参考に、実際のプロジェクトにSpring Data JPAを導入してみてください。


<!-- application.properties -->
spring.datasource.url=jdbc:mysql://localhost:3306/your_database
spring.datasource.username=root
spring.datasource.password=your_password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

<!-- Userエンティティクラス -->
import jakarta.persistence.Entity;
import jakarta.persistence.Id;

@Entity
public class User {
    @Id
    private Integer id;
    private String username;
    private String email;

    // Getter, Setter
}

<!-- UserRepositoryインターフェース -->
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Integer> {
    User findByUsername(String username);
}

<!-- UserServiceクラス -->
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    public User getUserByUsername(String username) {
        return userRepository.findByUsername(username);
    }
}

<!-- UserControllerクラス -->
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/users")
    public String getAllUsers(Model model) {
        model.addAttribute("users", userService.getAllUsers());
        return "users";
    }
}

この記事を通じて、Spring Data JPAを活用した効率的なデータベース操作の方法を学べたかと思います。これらの知識を活用して、データベースを使ったJavaアプリケーション開発に挑戦してみてください。

先生と生徒の振り返り会話

生徒

「Spring Data JPAを使えば、SQLを書かずにデータベース操作ができるんですね!とても便利です。」

先生

「その通りです。リポジトリインターフェースを活用すれば、簡単にデータの取得や保存ができます。ただし、必要に応じてカスタムクエリも書けるので、柔軟性もありますよ。」

生徒

「データベースの初期設定や初期データの投入も簡単にできるのがいいですね。」

先生

「そうですね。schema.sqldata.sqlを活用することで、開発効率をさらに高めることができます。」

生徒

「次は、もっと複雑なクエリやエンティティ間の関連を学んでみたいです!」

先生

「良い目標ですね。次回はエンティティのリレーションや、カスタムクエリの作成方法について詳しく説明しましょう!」

この記事を読んだ人からの質問

この記事を読んだ人からの質問
この記事を読んだ人からの質問

プログラミング初心者からのよくある疑問/質問を解決します

Spring Data JPAとは何ですか?初心者でも使えますか?

Spring Data JPAは、JavaのSpring Frameworkでデータベース操作を簡単にするライブラリです。リポジトリインターフェースを使用することで、SQLを直接書かずにデータの取得、保存、削除が可能です。初心者でも基本的な使い方を学べば簡単に利用できます。

application.propertiesに何を設定すればデータベースに接続できますか?

application.propertiesに、データベースの接続URL(例: jdbc:mysql://localhost:3306/your_database)、ユーザー名、パスワードを設定します。また、Hibernateの設定としてspring.jpa.hibernate.ddl-autoを「update」に設定することで、データベーススキーマの自動更新も可能です。

Spring Data JPAでfindAllメソッドは何に使いますか?

findAllメソッドは、指定したエンティティクラスに基づいてデータベース内の全てのデータを取得するために使用します。このメソッドはリポジトリインターフェースに組み込まれているため、追加のSQLを書く必要がありません。

findByUsernameのようなカスタムメソッドはどうやって作るのですか?

リポジトリインターフェースで「findBy+カラム名」という形式でメソッドを定義すると、自動的にそのカラムを条件とするクエリが生成されます。例えば、findByUsernameはusernameカラムを基準にデータを取得します。

schema.sqlとdata.sqlはどのように使いますか?

schema.sqlはデータベースのテーブル構造を定義するためのファイルで、data.sqlは初期データを投入するためのファイルです。Spring Bootのプロジェクト内のsrc/main/resourcesディレクトリに配置すると、アプリケーション起動時に自動的に実行されます。

Spring Data JPAを使う場合でもSQLを直接書く必要がありますか?

基本的なCRUD操作はリポジトリインターフェースで対応できますが、複雑なクエリが必要な場合は@Queryアノテーションを使用してSQLを直接記述することもできます。

リレーショナルデータベースでSpring Data JPAはどのように動作しますか?

Spring Data JPAは、エンティティクラスとリポジトリインターフェースを基にデータベース操作を行います。エンティティクラスにはテーブルの構造を、リポジトリインターフェースには操作方法を定義し、JPAがそれを基にデータ操作を実行します。

@Autowiredは何に使うのですか?

@Autowiredは、Springコンテナに登録されたBeanを自動的に注入するために使用されます。例えば、リポジトリやサービスクラスをコントローラーで使用する際に便利です。

データベーススキーマを更新する際の注意点は何ですか?

spring.jpa.hibernate.ddl-autoを「update」に設定すると、アプリケーション起動時にスキーマが自動更新されますが、誤ってデータを上書きしたり削除しないように注意が必要です。本番環境では「validate」または「none」を推奨します。

ThymeleafとSpring Data JPAを一緒に使う利点は何ですか?

Thymeleafを使用すると、Spring Data JPAで取得したデータを簡単にテンプレートに渡してHTML上で表示できます。これにより、バックエンドとフロントエンドの統合がスムーズになります。

PageとSliceの違いは何ですか?どちらを使えば良いですか?

Pageは総件数・総ページ数などのメタ情報を含み、一覧画面のページネーションに便利です。Sliceは「次があるか」だけを持ち、総件数のカウントを行わないため軽量です。総数表示が不要ならSlice、必要ならPageを選びます。

ページ番号は0始まりですか?1始まりですか?

Spring DataのPageRequestは0始まりです。UIが1始まりの場合は、受け取ったページ番号から1を引いてPageRequest.of(page - 1, size)のように調整します。
カテゴリの一覧へ
新着記事
JavaのHttpServletResponseWrapperを完全解説!初心者でも理解できるレスポンス処理のしくみ
JavaのScannerクラスの使い方を徹底解説!初心者でも簡単に学べる入力処理
JavaのArrayListクラスとaddメソッドを完全解説!初心者でもわかるリスト操作
Javaの@Idアノテーションを徹底解説!初心者でもわかるデータベースとの連携方法
人気記事
No.1
Java&Spring記事人気No1
Spring BootとJavaの互換性一覧!3.5/3.4/3.3はJava 21・17に対応してる?
No.2
Java&Spring記事人気No2
Javaのラムダ式で配列を扱う!Arrays.streamの基本と注意点を初心者向けに解説
No.3
Java&Spring記事人気No3
JavaのRuntimeExceptionを完全解説!初心者でもわかるjava.langパッケージの基礎
No.4
Java&Spring記事人気No4
JavaのBigDecimalクラスcompareToメソッド完全ガイド!初心者でもわかる大小比較の基本
No.5
Java&Spring記事人気No5
JavaのIntegerクラスの使い方を完全ガイド!初心者でもわかる整数操作
No.6
Java&Spring記事人気No6
Springの@Serviceアノテーションの使い方を徹底解説!初心者でもわかるSpring フレームワーク入門
No.7
Java&Spring記事人気No7
Javaの@SuppressWarningsアノテーションの使い方を完全ガイド!初心者でもわかる警告の抑制方法
No.8
Java&Spring記事人気No8
JSPとは何か?初心者向けにできること・仕組み・特徴をやさしく解説