【Spring Boot】クエリメソッドの命名規則

Java

こんにちは、かつコーチです。

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);
}

複数条件の組み合わせ

AndOrで複数条件を繋げることもできます。

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);

BookAuthorPriceという関連や複合語のフィールドは存在しないため、アプリケーション起動時にPropertyReferenceExceptionが発生します。

筆者も、キャメルケースの区切りを誤ってfindByAuthorNnameのように打ち間違え、起動時にスタックトレースを見てもすぐには気づけず、Entityのフィールド名と1文字ずつ照合して原因を見つけたことがあります。

✅ After:Entityのフィールド名と完全に一致させる

List<Book> findByAuthor_Name(int price); // author.nameへのネストしたプロパティアクセス

リレーション先のフィールドを指定する場合は、アンダースコア(_)で区切ると意図が明確になり、命名の衝突も避けられます。

エディタの補完機能を活用し、Entityのフィールド名をコピー&ペーストする習慣をつけるとミスを減らせます。

応用・一歩先の使い方

命名規則が向かないケース

クエリメソッドは手軽な反面、以下のようなケースには向いていません。

  • 3つ以上の条件を複雑に組み合わせる検索
  • 集計関数(SUMAVGなど)を使いたい場合
  • 複数テーブルを結合した独自の検索

このような場合は、次回扱う@QueryアノテーションでJPQLやネイティブSQLを直接書く方法に切り替えます。

まとめ

この記事のポイント

  • クエリメソッドは「動詞+By+フィールド名」の命名規則でSQLが自動生成される
  • AndOrGreaterThanContainingなどのキーワードで条件を組み立てられる
  • フィールド名のスペルミスは起動時にPropertyReferenceExceptionとして検出される
  • 条件が複雑になったら@Queryアノテーションへの切り替えを検討する

次に読むべき記事

  • @OneToMany・@ManyToOneでリレーションを組む
  • @Queryでカスタムクエリを書く
  • N+1問題とJOIN FETCHでの解決

タグ: Spring Boot, 中級者向け, データベース

タイトルとURLをコピーしました