Spring Data JPA入門!findAll()やfindBy**()の使い方などデータベース操作の基礎を学ぶ
生徒
「Spring Data JPAって何ですか?」
先生
「Spring Data JPAは、JavaのSpring Frameworkでデータベースとやり取りを簡単にするためのライブラリです。データの取得や保存を簡単にしてくれますよ。」
生徒
「それは便利そうですね!設定方法とか、使い方の基本も知りたいです。」
先生
「では、基本的な設定から実際のコード例まで順を追って説明していきますね!」
1. Spring Data JPAとは?
Spring Data JPAは、データベースとのやり取りを簡単にするためのSpring Frameworkの一部です。通常、SQLを直接書く必要があるデータ操作を、簡単なメソッドの呼び出しだけで実行できるようにしてくれます。また、リポジトリインターフェースを用いることで、自動的にCRUD(Create, Read, Update, Delete)操作を提供してくれるため、データベース操作がとてもスムーズになります。
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を指定し、usernameとpasswordにはそれぞれのデータベース情報を入力します。spring.jpa.show-sql=trueは、実行されるSQLをログに表示する設定です。
3. schema.sqlとdata.sqlでDBデータ準備
データベースのテーブルを自動生成したり、初期データを投入したい場合は、schema.sqlとdata.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メソッドでデータを取得する
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***で条件付きデータ取得
特定の条件に基づいてデータを取得したい場合、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で効率よく取り出す
大量データを一括取得するとメモリを圧迫します。PageableとSortを使えば、ページ単位で取り出し順序も指定できます。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 など
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 の扱い
永続化(保存・更新)はsave、一括はsaveAll、削除はdeleteById等を使います。読み取り時のfindByIdはOptionalを返すため、存在しない場合のハンドリングを忘れないようにします。更新系はトランザクション境界(@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)で柔軟に記述する
派生クエリで表現しづらい条件は@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.sqlとdata.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.sqlとdata.sqlを活用することで、開発効率をさらに高めることができます。」
生徒
「次は、もっと複雑なクエリやエンティティ間の関連を学んでみたいです!」
先生
「良い目標ですね。次回はエンティティのリレーションや、カスタムクエリの作成方法について詳しく説明しましょう!」