カテゴリ: Spring 更新日: 2026/01/30

Springの@Queryアノテーションを徹底解説!初心者でもわかるSpring Bootのカスタムクエリ

Springの@Queryアノテーション
Springの@Queryアノテーション

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

生徒

「Springフレームワークで@Queryアノテーションを見かけたんですけど、どういう使い方をするんですか?」

先生

@Queryアノテーションは、リポジトリにカスタムなSQLクエリを直接書いてデータベース操作を行うためのものだよ。」

生徒

「標準のCRUDメソッドではできないような複雑なクエリを使いたいときに便利なんですね?」

先生

「その通りだね。さっそく@Queryアノテーションの基本的な使い方を見ていこう!」

1. @Queryアノテーションとは?

1. @Queryアノテーションとは?
1. @Queryアノテーションとは?

Spring Data JPAの@Queryは、リポジトリインターフェースのメソッドに カスタムクエリを直接書ける仕組みです。メソッド名から自動生成される findBy...だけでは表現しづらい条件や結合を、明示的なクエリとして定義できます。 クエリ言語は基本的にエンティティ名とプロパティ名を使うJPQLで、 実テーブルやカラム名を使うネイティブSQLも指定可能です(後の章で詳しく扱います)。

使いどころのイメージを掴むために、初心者向けの短い例を見てみましょう。 たとえば「有効な顧客だけを取得したい」という要件があるとします。 メソッド名だけで書くと長くなりがちですが、@Queryならクエリを一目で把握できます。


import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;

public interface CustomerRepository extends JpaRepository<Customer, Long> {

  // JPQL:エンティティ名(Customer)とプロパティ名(active)を使う
  @Query("SELECT c FROM Customer c WHERE c.active = true")
  List<Customer> findActiveCustomers();
}

上記はとてもシンプルですが、Spring Boot + Spring Data JPA@Queryを使う感覚をつかむのに十分です。JPQLなので、データベースに依存せず、 エンティティ(Customer)とそのプロパティ(active)で条件を記述します。 「どこに何を書くのか?」が明確になり、読みやすく保守しやすいリポジトリを作れます。 まずは「必要な条件をJPQLで素直に書く」ことから始めるとスムーズです。

2. @Queryの基本的な使い方

2. @Queryの基本的な使い方
2. @Queryの基本的な使い方

それでは実際に@Queryを使ってみましょう。以下の例では、特定の価格以上の商品を検索するクエリを作成します。


import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {

    // 特定の価格以上の商品を検索するカスタムクエリ
    @Query("SELECT p FROM Product p WHERE p.price > :price")
    List<Product> findProductsByMinPrice(@Param("price") double price);
}

この例では、@Queryアノテーションを使って、priceというパラメータを渡し、指定された価格以上の商品を取得しています。

3. ネイティブSQLクエリを使う方法

3. ネイティブSQLクエリを使う方法
3. ネイティブSQLクエリを使う方法

@Queryアノテーションでは、JPQL(Java Persistence Query Language)だけでなく、ネイティブSQLも使用できます。nativeQuery=trueを指定することで、 実際のデータベースのSQL文を直接記述することが可能です。


import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {

    // ネイティブSQLクエリを使用して顧客を検索
    @Query(value = "SELECT * FROM customers WHERE email = :email", nativeQuery = true)
    Customer findCustomerByEmail(@Param("email") String email);
}

上記の例では、データベースの顧客テーブルから特定のメールアドレスの顧客情報を取得するためにネイティブクエリを使用しています。

4. @Queryと@Modifyingの組み合わせ

4. @Queryと@Modifyingの組み合わせ
4. @Queryと@Modifyingの組み合わせ

データの更新や削除を行う場合には、@Modifyingアノテーションを@Queryと組み合わせて使用します。 例えば、特定の商品の在庫数を一括で更新するクエリを以下のように記述します。


import org.springframework.data.jpa.repository.Modifying;
import org.springframework.transaction.annotation.Transactional;

@Repository
public interface InventoryRepository extends JpaRepository<Inventory, Long> {

    // 商品の在庫数を一括更新する
    @Modifying
    @Transactional
    @Query("UPDATE Inventory i SET i.stock = i.stock - :quantity WHERE i.id = :id")
    int updateStock(@Param("id") Long productId, @Param("quantity") int quantity);
}

このように、@Modifying@Transactionalを併用することで、更新系のクエリもシンプルに書けます。

5. @Queryアノテーションの注意点

5. @Queryアノテーションの注意点
5. @Queryアノテーションの注意点

@Queryを使用する際には、いくつかの注意点があります。まず、パラメータ名を間違えるとクエリ実行時にエラーが発生します。 また、JPQLではクラス名やフィールド名を使用するため、テーブルやカラム名ではない点に注意しましょう。

さらに、nativeQuery=trueを使用する場合、データベース固有のSQL構文に依存するため、データベースの移行時に問題が発生することがあります。 そのため、できるだけJPQLを使うことが推奨されます。

先生と生徒の会話

生徒

@Queryアノテーションについて理解できました!これを使えば、より柔軟にデータベースと連携できますね。」

先生

「その通り!標準のメソッドでは足りない部分を@Queryで補えるから、うまく活用していこう。」

6. パラメータバインディングの基本(LIKE・IN・BETWEEN)

6. パラメータバインディングの基本(LIKE・IN・BETWEEN)
6. パラメータバインディングの基本(LIKE・IN・BETWEEN)

@Queryアノテーションでは、@Paramで受け取った値をJPQLに安全に埋め込みます。初心者がつまずきやすいのがワイルドカードの扱いです。 部分一致はCONCATで確実に書き、複数条件はIN、期間検索はBETWEENを使います(Spring Boot + Spring Data JPAの定番パターン)。


// 名前にキーワードを含む商品を検索(部分一致:LIKE)
@Query("SELECT p FROM Product p WHERE LOWER(p.name) LIKE LOWER(CONCAT('%', :keyword, '%'))")
List<Product> searchByNameLike(@Param("keyword") String keyword);

// IDの集合に含まれる商品をまとめて取得(IN 句)
@Query("SELECT p FROM Product p WHERE p.id IN :ids")
List<Product> findByIds(@Param("ids") List<Long> ids);

// 期間で注文を検索(BETWEEN)
@Query("SELECT o FROM Order o WHERE o.createdAt BETWEEN :from AND :to")
List<Order> findOrdersBetween(@Param("from") LocalDateTime from,
                                @Param("to") LocalDateTime to);

SEOポイント:Spring Data JPA@Query パラメータバインディングは、LIKEINBETWEENの書き方を覚えると カスタムクエリの表現力が一気に上がります。

7. ページング・ソートを@Queryで実装する(Pageable / Sort / countQuery)

7. ページング・ソートを@Queryで実装する(Pageable / Sort / countQuery)
7. ページング・ソートを@Queryで実装する(Pageable / Sort / countQuery)

大量データはPageableでページング、Sortで並び替え。Page<T>を返すメソッドでは、複雑なJPQLやネイティブSQLの場合 countQueryの指定が重要です(総件数の高速取得でパフォーマンス最適化)。


import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

// JPQL + Pageable(カテゴリで絞り、ページング)
@Query(
  value = "SELECT p FROM Product p WHERE p.category = :category",
  countQuery = "SELECT COUNT(p) FROM Product p WHERE p.category = :category"
)
Page<Product> findByCategory(@Param("category") String category, Pageable pageable);

// Sortだけを引数で受けて並び替え
@Query("SELECT c FROM Customer c WHERE c.status = :status")
List<Customer> findByStatus(@Param("status") String status, Sort sort);

SEOポイント:Spring Boot@Query ページングソートは、PageablecountQueryのセットが基本。 カスタムクエリでもスケーラブルなデータ取得が可能です。

8. DTO/プロジェクションで必要な項目だけ返す(高速化の定石)

8. DTO/プロジェクションで必要な項目だけ返す(高速化の定石)
8. DTO/プロジェクションで必要な項目だけ返す(高速化の定石)

一覧画面などで全カラムは不要なことが多いです。select new(コンストラクタ式)やインターフェース・プロジェクションを使うと、 軽量なDTOだけを返せて描画が高速化します(Spring Data JPA プロジェクションの鉄板)。


// DTOコンストラクタ式(JPQL)
@Query("SELECT new com.example.dto.ProductSummary(p.id, p.name, p.price) " +
       "FROM Product p WHERE p.price > :minPrice")
List<ProductSummary> findSummary(@Param("minPrice") BigDecimal minPrice);

// インターフェース・プロジェクション(ネイティブでも可)
public interface ProductView {
  Long getId();
  String getName();
  BigDecimal getPrice();
}

@Query(value = "SELECT id, name, price FROM products WHERE price > :minPrice", nativeQuery = true)
List<ProductView> findViewNative(@Param("minPrice") BigDecimal minPrice);

SEOポイント:@Query DTOプロジェクションカスタムクエリ最適化。 返却データを必要最小限にしてネットワークとメモリを節約できます。

9. N+1問題を避けるフェッチ戦略(FETCH JOIN / DISTINCT / EntityGraph)

9. N+1問題を避けるフェッチ戦略(FETCH JOIN / DISTINCT / EntityGraph)
9. N+1問題を避けるフェッチ戦略(FETCH JOIN / DISTINCT / EntityGraph)

コレクションの遅延読み込みで発生するN+1問題は表示性能を大きく落とします。@QueryJOIN FETCHを使い、 必要な関連を一括ロードしましょう。重複行はDISTINCTで抑止するのが定石です。


// 注文とその明細を一括で取得(N+1回避)
// DISTINCTを付けて重複エンティティの復元を安定化
@Query("SELECT DISTINCT o FROM Order o JOIN FETCH o.items WHERE o.customer.id = :customerId")
List<Order> findOrdersWithItems(@Param("customerId") Long customerId);

// 参考:@EntityGraph 併用パターン(@Queryと使い分け)
@EntityGraph(attributePaths = {"items", "customer"})
@Query("SELECT o FROM Order o WHERE o.id = :id")
Optional<Order> findByIdWithRelations(@Param("id") Long id);

SEOポイント:Spring Data JPA @QueryでのFETCH JOINN+1問題対策の基本。 DISTINCT@EntityGraphを使い分けてカスタムクエリのパフォーマンスを最大化します。

まとめ

まとめ
まとめ

今回は、Springフレームワークの@Queryアノテーションについて詳しく解説しました。初心者でも理解できるように、基本的な使い方から、ネイティブSQLの使用方法、データの更新や削除のための@Modifyingアノテーションとの組み合わせまでカバーしましたね。

まず、@Queryアノテーションは、Spring Data JPAを使ってリポジトリ層にカスタムクエリを簡単に書ける非常に便利な機能です。findByメソッドのような標準メソッドでは実現できない複雑な検索条件や特定の条件に基づいたデータ取得が必要な場合に大いに役立ちます。

特にネイティブSQLを使うことで、データベースのパフォーマンスを最大限に引き出すことができるため、データベースごとに異なる最適化を行いたいときには効果的です。ただし、データベース移行時の互換性には注意が必要なので、基本的にはJPQLを使い、どうしても必要な場合にネイティブクエリを検討する方が良いでしょう。

また、データの更新には@Modifying@Transactionalを併用することで、安全にトランザクションを管理しながら効率的なデータ更新が可能です。特に大規模なシステムや高頻度なデータ変更が必要な場面ではこの機能を上手く活用することが重要です。

さらに、パラメータ名の指定ミスやJPQLとSQLの違いなど、いくつかの注意点についても解説しました。これらのポイントを押さえることで、より安全で効果的なクエリを作成することができます。

最後に、@Queryアノテーションを活用することで、開発の柔軟性が増し、コードの可読性も向上します。Spring Bootアプリケーションを開発する際には、是非@Queryを活用してみてください。

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

生徒

「今回学んだ@Queryアノテーションについて、色々な使い方があるんですね。標準のメソッドだけでなく、より柔軟にクエリが書けるのはとても便利だと思いました。」

先生

「そうだね。実際のプロジェクトでは、@Queryを使うことで複雑なデータ取得が可能になるよ。例えば、検索機能の実装やデータ分析に活用できるんだ。」

生徒

「それに、ネイティブSQLも使えるのは驚きました。データベースに依存した最適化ができるので、パフォーマンスを意識したいときに便利ですね。」

先生

「その通り。けれど、基本的にはJPQLを使ってデータベースに依存しない書き方を心掛けよう。ただ、どうしても必要なときにはネイティブSQLをうまく使い分けると良いよ。」

生徒

「次はデータ更新の@Modifying@Transactionalを使った高度な操作も学んでみたいです!」

先生

「いい意欲だね!それじゃあ、次回は@Modifyingを使ったバッチ処理や複数レコードの更新について学んでいこう!」

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

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

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

Spring Data JPAで@Queryアノテーションとは何をするための機能ですか?Spring Bootのリポジトリにカスタムクエリを書く意味を、初心者向けにJPQLとSQLのキーワードを交えて知りたいです。

@Queryアノテーションは、Spring Data JPAのリポジトリインターフェースにカスタムクエリを直接記述して実行するための仕組みです。標準のCRUDやfindByでは表現しにくい複雑な条件、結合、特定カラムの選択などをJPQLまたはネイティブSQLで柔軟に書けるため、Spring Bootアプリのデータアクセスを最適化できます。

findByなどの派生クエリと@Queryの使い分けはどう考えれば良いですか?複雑な結合や特定カラムの抽出がある場合の判断基準をSpring Bootの初心者視点で知りたいです。

単純な等価条件や並び替えなら派生クエリで十分ですが、複数条件の組み合わせ、結合、集約、必要なカラムだけの取得など表現力が必要な場合は@Queryを選びます。Spring Data JPAでまず派生クエリを試し、読みづらくなったら@Queryで明示的なJPQLもしくはネイティブSQLに切り替えるのが実務的な指針です。

Springの学習を効率化したい方へ

この記事の内容をもっと深く知るには、以下の入門書が最適です。

Spring Framework超入門をAmazonで見る
カテゴリの一覧へ
新着記事
New1
Spring
SpringDataJPAのJPAクエリメソッド「NotLike」の使い方を完全ガイド!初心者向け解説
更新記事
New2
Spring
SpringDataJPAのJPAクエリメソッド「Like」の使い方を完全ガイド!初心者向け解説
更新記事
New3
Java
JavaのLocalDateTimeクラスとplusMinutesメソッドを完全ガイド!初心者でもわかる分単位の時間操作
新規投稿
New4
Spring
SpringDataJPAのJPAクエリメソッド「IsNotNull」と「NotNull」の使い方を完全ガイド!初心者向け解説
更新記事
人気記事
No.1
Java&Spring記事人気No1
Spring
Spring BootとJavaの互換性一覧!3.5/3.4/3.3はJava 21・17に対応してる?
No.2
Java&Spring記事人気No2
Java
JavaのBooleanクラスの使い方を完全ガイド!初心者でもわかる真偽値の操作
No.3
Java&Spring記事人気No3
JSP
JSPの基本タグ一覧と使い方まとめ!実務で使えるタグを紹介
No.4
Java&Spring記事人気No4
Java
JavaのIOExceptionクラス徹底解説!初心者向けファイル入出力エラー対策ガイド
No.5
Java&Spring記事人気No5
JSP
JSPでif文・for文を使う方法!初心者でもわかるJavaとの違いと使い方
No.6
Java&Spring記事人気No6
Spring
SpringのBindingResultを完全ガイド!初心者でもわかる入力チェックとエラー処理
No.7
Java&Spring記事人気No7
Spring
SpringのModelクラスとaddAttributeメソッドの使い方を完全ガイド!初心者でも安心
No.8
Java&Spring記事人気No8
Spring
SpringDataJPAのJPAクエリメソッド「EndingWith」の使い方を完全ガイド!初心者向け解説