JPQL入門(JPA)

JPQL入門(JPA)

JPAでDB(正確にはエンティティ)からデータを取得するSQLをJPQLと言います。

SQLでfrom句に書いていたのはテーブル名ですが、JPQLではfrom句にはエンティティを書きます。(ここが重要)

@QueryアノテーションでJPQLを記述しますが、通常のSQL構文と少しだけ構文が変わります。

以下は簡単なJPQLの例です。

上記では、mがエイリアスです。select *ではなくselect mとします。value = は省略可能です。

JPQLで注意しないといけないのはテーブル名はエンティティクラス名を書く、カラム名はエンティティクラスのフィールド名を書く、という点です。

実際のテーブル名がemp_masterであってもそのテーブルに対応するエンティティクラスがEmpMasterクラスであれば、JPQL文ではEmpMasterと書きます。

UPDATE文やDELETE文を書く

JPQL文でUPDATE文やDELETE文を書くにはアノテーションがいくつか増えます。

アノテーション 意味
@Transactional メソッドが異常終了すればロールバックされる
@Modifying update文を書くときに変更

コーディング例は以下の通りです。

LIKE検索をする

JPQLではLIKE検索ができます。バインド変数に%を付ける場合などは以下の通り記述します。

JPQLは色々制約がある

JPQLは色々と制約があるので、その場合はSQL文を書くしかありません。

SQLを記述する場合は、nativeQuery=trueとします。

以下、例です。

参考サイト:JPQLでFROM句に副問い合わせが使えない

ちなみにMySQLの日付計算で使うinterval,DAY,MONTH,YEARなどもJPQLでは使えないのでnativeQuery=trueにする必要があります。

エンティティに紐づかないSelect句の場合エラーとなる

JPQLが簡単なら良いのですが、例えば年月ごとに集計を求めるGroupなどを使う場合色々ややこしかったりします。

エンティティクラス

こんなエンティティがある場合にJPQLで年月日ではなく、年月をSelect句に入れるとエラーとなります。

これはLocalDateに対して年月にフォーマットした値になっているため、エラーとなります。

回避方法は新たにクラスを作成し、そのインスタンス生成時のコンストラクタに文字列として突っ込んであげます。select new(コンストラクタ式)を使用する場合はnativeQueryは使えませんのでご注意ください。

SampleEntityはこんな感じで単なるクラスです。

これでOKです。

@EmbeddedId

主キーが一つであれば、@Idでよいのですが、複合主キーの場合は@IdClassや、@EmbeddedIdを使用します。@IdClassだと冗長になるので

エンティティは以下のように定義します。

implements Serializableしないとエラーとなります。で、この複合主キーに対して@Embeddableアノテーションを付加します。

リポジトリクラスは以下のように定義します。

複合主キーの場合は、@Queryの書き方に注意しないといけなくて、@Embeddedを使用する場合は、JPQLがm.id.empnoというようになります。

findByIdの引数に複合主キーを指定する

JpaRepositoryがデフォルトで用意しているfindByIdメソッドの引数に複合主キーを指定してみます。先ほど書いたエンティティを使用します。

サービスクラスからリポジトリをDIして呼び出します。

メソッド名からJPQLを生成する

メソッド名に一定の決まりがあって、その名前からJPQLを生成することができます。

Employeeというエンティティがあったとして、リポジトリに

というメソッドを作成すると

となります。

条件が2つある場合はfindByNameAndEmpnoとします。

このメソッドは以下を意味します。

以下はメソッド名に指定すると特別に意味を持ちます。

単語 メソッド名 JPQL
By findByXX where XX = :XX
And findByXXAndYY where XX = :XX and YY = :YY
Or findByOr where XX = :XX or YY = :YY
Like findByXXLike where XX like :XX
NotLike findByXXNotLike where XX not like :XX
Containing findByXXContaining where XX like ‘%:XX%’
IsNull findByXXIsNull where XX is null
IsNotNull findByXXIsNotNull where XX is not null
NotNull findByXX where XX is not null
Between findByXXBetween where XX between :XX1 and :XX2
LessThan findByXXLessThan where XX < :XX(数値) | | GreaterThan | findByXXGreaterThan | where XX > :XX(数値)
After findByXXAfter where XX > :XX(日時)
Before findByXXBefore where XX < :XX(日時)
OrderBy findByXXOrderByYYAsc where XX = :XX order by YY asc
Not findByXXNot where XX <> :XX
In findByXXIn where XX in (?,?…)
NotIn findByXXNotIn where XX not in (?,?…)
True findByXXTrue where XX = true
False findByXXFalse where XX = false
StartingWith findByXXStartingWith where XX like ‘:XX%’
EndingWith findByXXEndingWith where XX like ‘%:XX’

@EmbeddedIdを使用していると命名規則がややこしい

@EmbeddedIdを使用している場合(複合主キー)、メソッド名がちょっとやっかいです。以下のような複合主キーのエンティティでPKを使用したい場合はメソッド名に@EmbeddedIdを付けたフィールド名を付けないと行けなくなります。

例えば、empnoで検索したい場合は

となります。

nativeな関数を使う方法

各RDBの関数をJPQLで使用したい場合

というようにします。

@QueryHintsを使用して大量データをフェッチする

@QueryHintsアノテーションを使用するとフェッチサイズを調整することができます。

フェッチサイズは@QueryHintのvalue属性に文字列で指定します。

nameにはorg.hibernate.jpa.QueryHints.HINT_FETCH_SIZEを指定します。以下はフェッチサイズを1000にした例です。

@EntityListeners(AuditingEntityListener.class)で最終更新情報を設定する

エンティティに@EntityListeners(AuditingEntityListener.class)アノテーションを付与すると、登録者、更新者、登録時間、更新時間を設定することができます。

設定したいプロパティにアノテーションを付与します。

アノテーション 意味 クラス
@CreatedBy 登録者 String
@CreatedDate 登録日時 LocalTime
@LastModifiedBy 更新者 String
@LastModifiedBy 更新日時 LocalTime

上記アノテーションを各プロパティに付与します。

jpa-named-queries.propertiesファイルを使用してJPQLをpropertiesに記述する

propertiesファイルにクエリーを記述することができます。デフォルトでは、META-INF/jpa-named-queries.propertiesに記述します。

リポジトリインターフェースの@Query(name=Sample.find)というように記述しこのname属性に指定した値とマッピングするJPQLをMETA-INF/jpa-named-queries.propertiesに記述します。

jpa-named-queries.properties

これでMETA-INF/jpa-named-queries.propertiesに記述することができました。

deleteメソッドよりもdeleteInBatchメソッドを使用する

Spring Data JPAではあらかじめdeleteメソッドが用意されているのですが、複数行削除する場合はその行数delete文が発行されてしまいます。その為deleteInBatchメソッドでバルクデリートしたほうが良いです。

deleteAllメソッドよりもdeleteAllInBatchメソッドを使用する

deleteAllメソッドもあらかじめ用意されているメソッドなのですが、全件削除してくれるのですが、レコード件数分delete文が実行されるだけです。その為、通信が多くなります。

deleteAllメソッドを使用するなら、deleteAllInBatchメソッドがありますので、そちらを使用すればバルクデリートすることが可能です。

スポンサーリンク
  • このエントリーをはてなブックマークに追加
スポンサーリンク

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA