カテゴリ: Spring 更新日: 2026/06/26

SpringのJPQLと@Queryの使い方を完全ガイド!ネイティブSQLとの違いも解説

JPQL/@Queryの書き方と実例:ネイティブSQLとの使い分け
JPQL/@Queryの書き方と実例:ネイティブSQLとの使い分け

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

生徒

「SpringでSQLっぽいことをしたいときって、どうやって書けばいいんですか?」

先生

「Spring Data JPAでは、JPQLというクエリ言語や@Queryアノテーションを使って柔軟にデータを取得できますよ。」

生徒

「SQLとは違うんですか?ネイティブSQLとの違いも知りたいです!」

先生

「では、JPQLとネイティブSQLの違い、@Queryの使い方、使い分けについて一緒に見ていきましょう。」

1. JPQLとは?SQLとの違いを解説

「1. JPQLとは?SQLとの違いを解説」の重要ポイントを、初心者の方にも分かりやすく簡潔に解説します。

1. JPQLとは?SQLとの違いを解説
1. JPQLとは?SQLとの違いを解説

JPQL(Java Persistence Query Language)は、Javaのエンティティクラスを操作するためのクエリ言語です。SQLと構文は似ていますが、テーブル名ではなくエンティティ名やフィールド名を使います。

たとえば、ユーザーをID順に取得するJPQLは以下のようになります。


@Query("SELECT u FROM User u ORDER BY u.id ASC")
List<User> findAllUsers();

このように、Userというのはテーブルではなくエンティティ名を指しています。u.idもカラムではなく、エンティティのプロパティ名です。

2. @QueryアノテーションでJPQLを使う方法

2. @QueryアノテーションでJPQLを使う方法
2. @QueryアノテーションでJPQLを使う方法

Spring Data JPAでは、@Queryアノテーションを使うことで、メソッド名に依存しないクエリを自由に記述できます。

例えば、「名前でユーザーを検索する」場合は以下のように記述します。


@Query("SELECT u FROM User u WHERE u.name = :name")
User findByName(@Param("name") String name);

:nameはパラメータで、@Paramで指定することで値をバインドできます。JPQLでは型安全なエンティティベースの記述ができ、リファクタにも強く、保守性も高いのが特長です。

3. ネイティブSQLの使い方と@QueryのnativeQuery属性

3. ネイティブSQLの使い方と@QueryのnativeQuery属性
3. ネイティブSQLの使い方と@QueryのnativeQuery属性

JPQLではできない複雑なSQLやデータベース固有の関数を使いたいときには、ネイティブSQL(生のSQL)を使うことができます。@QuerynativeQuery = trueを指定することで可能です。


@Query(value = "SELECT * FROM users WHERE email = ?1", nativeQuery = true)
User findByEmail(String email);

この場合、テーブル名はusersのように実際のデータベースのスキーマ名を使用します。エイリアスもSQLの書き方と同様に使えます。

4. JPQLとネイティブSQLの使い分けポイント

「4. JPQLとネイティブSQLの使い分けポイント」の重要ポイントを、初心者の方にも分かりやすく簡潔に解説します。

4. JPQLとネイティブSQLの使い分けポイント
4. JPQLとネイティブSQLの使い分けポイント

JPQLとネイティブSQLは、使い分けが重要です。以下のような基準で選ぶと良いでしょう。

  • JPQLを使う場面:基本的な検索・更新・削除、エンティティベースで完結する処理
  • ネイティブSQLを使う場面:データベースの特有の構文、複雑な結合や関数、パフォーマンスチューニング

例えば、PostgreSQLのjsonbやMySQLのLIMITなどはJPQLでは扱いづらいため、ネイティブSQLが必要です。

5. JPQLでのJOIN文の書き方と注意点

5. JPQLでのJOIN文の書き方と注意点
5. JPQLでのJOIN文の書き方と注意点

JPQLでもJOINを使ってテーブル(エンティティ)間のリレーションを扱うことができます。


@Query("SELECT o FROM Order o JOIN o.customer c WHERE c.name = :name")
List<Order> findOrdersByCustomerName(@Param("name") String name);

このように、JOINではエンティティのプロパティをたどる形で記述します。SQLのようにテーブル名を直書きすることはありません。

6. DTOを使ったJPQLクエリの書き方

6. DTOを使ったJPQLクエリの書き方
6. DTOを使ったJPQLクエリの書き方

JPQLでは、DTO(データ転送オブジェクト)を使って必要なフィールドだけを取り出すこともできます。クエリ内でnewを使ってDTOを生成します。


@Query("SELECT new com.example.dto.UserDto(u.name, u.email) FROM User u")
List<UserDto> findUserDtos();

この形式は、パフォーマンスを意識した設計にも有効で、必要なカラムだけを選択してデータ転送量を最適化できます。

7. @Modifyingと@Queryの組み合わせで更新系JPQLを書く

「7. @Modifyingと@Queryの組み合わせで更新系JPQLを書く」の重要ポイントを、初心者の方にも分かりやすく簡潔に解説します。

7. @Modifyingと@Queryの組み合わせで更新系JPQLを書く
7. @Modifyingと@Queryの組み合わせで更新系JPQLを書く

更新系クエリ(UPDATE/DELETE)は@Modifyingアノテーションを併用して書きます。トランザクション制御も必要なので注意しましょう。


@Transactional
@Modifying
@Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
void updateUserStatus(@Param("id") Long id, @Param("status") String status);

@Transactionalをメソッドに付けることで、更新クエリがトランザクション内で安全に実行されます。

8. @Queryを使うときのよくあるエラーと対処法

8. @Queryを使うときのよくあるエラーと対処法
8. @Queryを使うときのよくあるエラーと対処法

JPQL/ネイティブSQLの@Queryでありがちなエラーには以下のようなものがあります。

  • エンティティ名とテーブル名の混同(JPQLではエンティティ名)
  • ネイティブSQLなのにnativeQuery = trueを付け忘れ
  • 引数の名前と:paramの不一致

こうしたエラーはIDEの補完やユニットテストで事前に気づくようにすると、開発効率が上がります。

まとめ

まとめ
まとめ

SpringのJPQLと@Queryを理解すると、Spring Data JPAでのデータ取得や検索処理をより柔軟に書けるようになります。通常、Spring Data JPAではfindByNameやfindByEmailのようにメソッド名から自動でクエリを作成できますが、条件が複雑になったり、JOINを使ったり、DTOへ必要な値だけを取得したりしたい場合には、@Queryを使ったJPQLの記述が役立ちます。JPQLはSQLに似た書き方ですが、テーブル名やカラム名ではなく、Javaのエンティティ名とフィールド名を使う点が大きな違いです。

JPQLを使うと、データベースの物理的なテーブル構造に直接依存しすぎず、エンティティ中心の考え方で検索処理を書けます。たとえばUserエンティティのnameやemailを条件にした検索では、usersテーブルやuser_nameカラムではなく、Userやu.nameのようにJavaのクラスとプロパティを使います。このため、Spring BootやSpring Data JPAでエンティティ設計を中心に開発している場合、JPQLは読みやすく保守しやすいクエリになります。

一方で、ネイティブSQLは実際のテーブル名やカラム名を使って書くため、データベース固有の機能を使いたい場合に向いています。PostgreSQL、MySQL、Oracle、SQL Serverなど、それぞれのデータベースが持つ独自関数や高度なSQLを使いたい場合は、@QueryにnativeQuery=trueを指定します。ただし、ネイティブSQLはデータベース依存が強くなるため、基本的な検索やエンティティ中心の処理では、まずJPQLを検討するとよいです。

JPQLと@Queryの基本を整理

@Queryは、Repositoryのメソッドに直接クエリを指定できるアノテーションです。メソッド名だけでは表現しにくい検索条件や並び替えを、JPQLとして明示的に書けます。JPQLではエンティティ名とフィールド名を使うため、Javaコードと対応関係を確認しながら書くことが大切です。


public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT u FROM User u ORDER BY u.id ASC")
    List<User> findAllUsers();

}

この例では、Userエンティティをidの昇順で取得しています。SELECT u FROM User uのUserはテーブル名ではなくエンティティ名です。u.idもデータベースのカラム名ではなく、Userクラスのidフィールドを指しています。初心者は、JPQLではデータベースではなくJavaのエンティティを見る、と覚えると理解しやすいです。

名前付きパラメータで条件検索する

@Queryでは、:nameのような名前付きパラメータを使って、メソッドの引数をクエリに渡せます。@Paramの名前とJPQL内のパラメータ名を一致させることが重要です。


public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT u FROM User u WHERE u.name = :name")
    User findByName(@Param("name") String name);

}

このコードでは、引数nameの値がJPQLの:nameに渡されます。@Param("name")とクエリ内の:nameが一致していないとエラーになるため、文字の打ち間違いに注意しましょう。検索条件が複数ある場合も、名前付きパラメータを使うと読みやすくなります。


public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT u FROM User u WHERE u.name = :name AND u.email = :email")
    User findByNameAndEmail(@Param("name") String name, @Param("email") String email);

}

このように、複数条件でもJPQLを使えば分かりやすく書けます。メソッド名が長くなりすぎる場合や、条件が複雑な場合は@Queryを使うと保守しやすくなります。

JOINを使った関連エンティティの検索

JPQLでは、エンティティ同士の関連をたどってJOINできます。SQLのようにテーブル名と結合条件を直接書くのではなく、エンティティの関連フィールドを使って書くのが特徴です。


public interface OrderRepository extends JpaRepository<Order, Long> {

    @Query("SELECT o FROM Order o JOIN o.customer c WHERE c.name = :name")
    List<Order> findOrdersByCustomerName(@Param("name") String name);

}

この例では、Orderエンティティからcustomerフィールドをたどり、Customerのnameを条件に注文情報を取得しています。JOIN o.customer cのように、エンティティのプロパティを使うため、Java側の関連定義を理解しておくことが重要です。

DTOで必要な値だけを取得する

一覧画面や検索結果では、エンティティ全体ではなく、名前とメールアドレスだけなど、必要な項目だけを取得したい場合があります。そのようなときは、JPQLでDTOを直接生成できます。


public class UserDto {

    private String name;
    private String email;

    public UserDto(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }
}

public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT new com.example.dto.UserDto(u.name, u.email) FROM User u")
    List<UserDto> findUserDtos();

}

DTOを使うと、画面表示に必要なデータだけを取得できるため、不要なデータの取得を減らせます。ただし、JPQL内でnewを使う場合は、DTOのパッケージ名を含めた完全なクラス名と、コンストラクタの引数順に注意しましょう。

ネイティブSQLを使う場面

JPQLでは表現しにくいSQLや、データベース固有の関数を使いたい場合は、ネイティブSQLを使います。@QueryのvalueにSQLを記述し、nativeQuery=trueを指定します。


public interface UserRepository extends JpaRepository<User, Long> {

    @Query(value = "SELECT * FROM users WHERE email = ?1", nativeQuery = true)
    User findByEmailNative(String email);

}

ネイティブSQLでは、usersのような実際のテーブル名を使います。JPQLと違って、エンティティ名ではありません。SQLの知識をそのまま使える反面、データベースのテーブル構造や方言に依存しやすくなるため、使いどころを見極めることが大切です。

更新系クエリではModifyingとTransactionalを使う

@QueryでUPDATEやDELETEを実行する場合は、@Modifyingを付けます。また、更新処理はトランザクションの中で行う必要があるため、@Transactionalも併用します。


public interface UserRepository extends JpaRepository<User, Long> {

    @Transactional
    @Modifying
    @Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
    void updateUserStatus(@Param("id") Long id, @Param("status") String status);

}

SELECTのような取得系クエリと違い、UPDATEやDELETEはデータベースの内容を変更します。そのため、@Modifyingを付け忘れると正しく実行できません。さらに、トランザクション管理も必要になるため、更新系の@Queryでは@Transactionalの有無も確認しましょう。

よくあるエラーと確認ポイント

JPQLと@Queryで初心者がつまずきやすいのは、エンティティ名とテーブル名の混同です。JPQLではUserやOrderのようなエンティティ名を使いますが、ネイティブSQLではusersやordersのようなテーブル名を使います。また、JPQLではフィールド名を使うため、データベースのカラム名をそのまま書くとエラーになることがあります。

もう一つ多いのが、@Paramの名前とJPQL内のパラメータ名の不一致です。@Param("name")と書いたなら、JPQL側も:nameにする必要があります。小さなスペルミスでも実行時エラーにつながるため、Repositoryのテストを書いて早めに確認することが大切です。

Spring、Spring Boot、Spring Data JPA、JPQL、@Query、ネイティブSQL、nativeQuery、Repository、JpaRepository、Entity、DTO、JOIN、@Param、@Modifying、@Transactional、エンティティ名、テーブル名、フィールド名、SQL、データベース検索、更新クエリ、削除クエリ、パフォーマンス、保守性といったキーワードは、JPAの検索処理を学ぶうえで重要です。これらを関連づけて理解すると、単純なfindByだけでは対応しにくい検索や更新処理も実装しやすくなります。

初心者は、まずJPQLでSELECT文を書き、エンティティ名とフィールド名を使う感覚を身につけるとよいです。次に@Paramで条件を渡す検索、JOINを使った関連エンティティの検索、DTOで必要な項目だけを取得する方法へ進むと理解しやすくなります。最後に、ネイティブSQLと@Modifyingを学ぶと、より実務的なデータアクセス処理に対応できるようになります。

JPQLと@Queryは、Spring Data JPAの検索処理を柔軟にするための強力な機能です。基本的な検索はメソッド名クエリで十分ですが、複雑な条件やJOIN、DTO取得、更新処理が必要な場合は@Queryが役立ちます。JPQLとネイティブSQLの違いを理解し、目的に合わせて使い分けることで、読みやすく保守しやすいSpringアプリケーションを作っていきましょう。

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

生徒

JPQLはSQLに似ていますが、テーブル名ではなくエンティティ名を使うことが分かりました。

先生

その通りです。JPQLでは、データベースのテーブルではなくJavaのエンティティを対象にして書きます。

生徒

@Queryを使うと、Repositoryのメソッドに自由な検索条件を書けるのですね。

先生

はい。メソッド名だけでは長くなりすぎる検索や、JOINを使う検索に向いています。

生徒

:nameのようなパラメータは、@Paramの名前と一致させる必要があるのですね。

先生

はい。名前が一致していないと、実行時にエラーになることがあります。

生徒

ネイティブSQLを使う場合は、nativeQuery=trueを指定して、実際のテーブル名やカラム名を書くのですね。

先生

その理解で大丈夫です。データベース固有のSQLを使いたい場合に便利です。

生徒

DTOを使うと、必要な項目だけを取得できるので、一覧画面などで便利そうです。

先生

はい。不要なデータを取得しない設計にできるため、画面表示用のデータ取得でよく使われます。

生徒

UPDATEやDELETEを書くときは、@Modifyingと@Transactionalが必要なのですね。

先生

その通りです。取得系と更新系では必要なアノテーションが違うため、忘れずに確認しましょう。

生徒

JPQLとネイティブSQLの違いを意識して使い分けることが大切だと分かりました。

先生

はい。基本はJPQL、データベース固有の処理や複雑なSQLが必要なときはネイティブSQLという考え方で、保守しやすいRepositoryを作っていきましょう。

Spring FrameworkやThymeleafを使った Webアプリ開発の全体像をやさしく理解したい人には、 この入門書が定番です。

Spring Framework超入門をAmazonで見る

※ Amazon広告リンク

カテゴリの一覧へ
新着記事
New1
Spring
Spring の@RequestParamの使い方!テキストボックス、ラジオボタン、チェックボックス、セレクトボックスの値を受け取る。
更新記事
New2
JSP
EL式の基本構文まとめ!${}で使う書き方のルールを解説
更新記事
New3
Java
JavaのBigIntegerとisProbablePrimeメソッドを完全解説!初心者でもわかる素数判定
更新記事
New4
JSP
JSPで発生する主なエラーとは?初心者向けに原因と対処法をやさしく解説
新規投稿
人気記事
No.1
Java&Spring記事人気No1
JSP
JSPのおすすめ学習・用語まとめ【2026年最新版】初心者が知っておきたい基本をやさしく解説
No.2
Java&Spring記事人気No2
Java
Javaのクラスとインスタンス化、コンストラクタの使い方完全ガイド!初心者でもわかるオブジェクト指向の基礎
No.3
Java&Spring記事人気No3
Spring
Springの@Serviceアノテーションの使い方を徹底解説!初心者でもわかるSpring フレームワーク入門
No.4
Java&Spring記事人気No4
Spring
Thymeleaf(タイムリーフ)入門!初心者でもわかるSpring Bootとテンプレートエンジンの使い方
No.5
Java&Spring記事人気No5
Spring
Javaの@PreAuthorizeアノテーションを完全ガイド!初心者でもわかるメソッドセキュリティ設定
No.6
Java&Spring記事人気No6
Spring
Springの@Queryアノテーションを徹底解説!初心者でもわかるSpring Bootのカスタムクエリ
No.7
Java&Spring記事人気No7
Java
JavaのExceptionクラスを完全解説!初心者でも理解できる例外処理の基本
No.8
Java&Spring記事人気No8
JSP
JSPでCSSやJSを読み込む基本!外部ファイルのパス指定に注意しよう