こんにちは、かつコーチです。
findAll()やfindById()は便利ですが、「価格が3000円以上の書籍だけ取得したい」のような条件検索はどうすればよいのでしょうか。
Spring Data JPAには、クエリメソッドというメソッド名だけでSQLを組み立ててくれる仕組みがあります。
今回はその命名規則を整理していきます。
クエリメソッドとは
メソッド名からSQLが生成される仕組み
クエリメソッドとは、Repositoryインターフェースに特定のルールでメソッドを定義するだけで、Spring Data JPAが自動的にSQLを生成してくれる機能です。
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByAuthorName(String authorName);
}
このメソッドを定義するだけで、Spring Data JPAが起動時にメソッド名を解析し、WHERE author_name = ?に相当するSQLを自動生成します。
メソッド名は「動詞+By+条件」という構造になっており、Byの後ろにEntityのフィールド名を続けるのが基本ルールです。
なぜこの仕組みが必要なのか
条件検索のたびにSQLを手書きしていると、タイプミスやSQLインジェクションのリスクが増えます。
クエリメソッドを使えば、コンパイル時にフィールド名の存在チェックも働くため、存在しないフィールド名を指定した場合は起動時にエラーとして検出できます。
命名規則の実践
基本の検索条件
| メソッド名の例 | 生成されるSQLのイメージ |
|---|---|
findByTitle(String title) | WHERE title = ? |
findByPriceGreaterThan(int price) | WHERE price > ? |
findByPriceBetween(int min, int max) | WHERE price BETWEEN ? AND ? |
findByTitleContaining(String keyword) | WHERE title LIKE %?% |
findByTitleStartingWith(String prefix) | WHERE title LIKE ?% |
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByPriceGreaterThan(int price);
List<Book> findByTitleContaining(String keyword);
List<Book> findByPriceBetween(int min, int max);
}
複数条件の組み合わせ
And・Orで複数条件を繋げることもできます。
List<Book> findByAuthorNameAndPriceGreaterThan(String authorName, int price);
List<Book> findByTitleContainingOrAuthorNameContaining(String titleKeyword, String authorKeyword);
条件が3つ、4つと増えてくると、メソッド名が非常に長くなり可読性が落ちてきます。
その場合は次回解説する@Queryアノテーションでの記述に切り替えるのが一般的です。
並び替え・件数制限
List<Book> findByAuthorNameOrderByPriceDesc(String authorName);
List<Book> findTop3ByOrderByPriceDesc();
OrderBy+フィールド名+Asc/Descで並び順を指定でき、findTop3Byのように件数を絞り込むことも可能です。
つまずきやすいポイント
フィールド名のスペルミスに気づけない
❌ Before:フィールド名を打ち間違える
// Entityのフィールド名は price だが author.price だと思い込んで書いてしまった
List<Book> findByAuthorPriceGreaterThan(int price);
BookにAuthorPriceという関連や複合語のフィールドは存在しないため、アプリケーション起動時にPropertyReferenceExceptionが発生します。
筆者も、キャメルケースの区切りを誤ってfindByAuthorNnameのように打ち間違え、起動時にスタックトレースを見てもすぐには気づけず、Entityのフィールド名と1文字ずつ照合して原因を見つけたことがあります。
✅ After:Entityのフィールド名と完全に一致させる
List<Book> findByAuthor_Name(int price); // author.nameへのネストしたプロパティアクセス
リレーション先のフィールドを指定する場合は、アンダースコア(_)で区切ると意図が明確になり、命名の衝突も避けられます。
エディタの補完機能を活用し、Entityのフィールド名をコピー&ペーストする習慣をつけるとミスを減らせます。
応用・一歩先の使い方
命名規則が向かないケース
クエリメソッドは手軽な反面、以下のようなケースには向いていません。
- 3つ以上の条件を複雑に組み合わせる検索
- 集計関数(
SUM・AVGなど)を使いたい場合 - 複数テーブルを結合した独自の検索
このような場合は、次回扱う@QueryアノテーションでJPQLやネイティブSQLを直接書く方法に切り替えます。
まとめ
この記事のポイント
- クエリメソッドは「動詞+By+フィールド名」の命名規則でSQLが自動生成される
And・Or・GreaterThan・Containingなどのキーワードで条件を組み立てられる- フィールド名のスペルミスは起動時に
PropertyReferenceExceptionとして検出される - 条件が複雑になったら
@Queryアノテーションへの切り替えを検討する
次に読むべき記事
- @OneToMany・@ManyToOneでリレーションを組む
- @Queryでカスタムクエリを書く
- N+1問題とJOIN FETCHでの解決
タグ: Spring Boot, 中級者向け, データベース