5
Mar 2024
by
健雄 尹
Spring Data Jpaが提供する機能を調べてみよう
Query Methodの三つの機能
- メソッド名前でクエリ作成
- メソッド名前でJPA NamedQuery呼び出し
@Query
アノテーションを使いレポジトリインタフェースに直接クエリを定義
メソッド名前でクエリ作成
Spring Data JPAがメソッドの名前を分析してJPQLクエリを実行してくれる。
注意点:
エンティティの名前が変更されると必ずインタフェースに定義したメソッドの名前も一緒に変更する必要がある、そうでないとアプリケーションを立ち上げる時点でエラーが生じる。こうやってアプリケーションのロード時にエラーを検知できるのがSpring Data JPAのすごく大きい長所である。
純粋なJPA Repositoryの場合
- ユーザの名前と歳(age)でユーザを検索する場合
public List<User> findByUsernameAndAgeGreaterThan(String username, int age) { return em.createQuery("select u from User u where u.username = :username and m.age > :age") .setParameter("username", username) .setParameter("age", age) .getResultList(); }
メソッド名前でクエリ生成機能の場合
- Spring Data JPAはメソッドの名前を分析しJPQLを生成して実行してくれる。
public interface UserRepository extends JpaRepository<User, Long> { List<User> findByUsernameAndAgeGreaterThan(String username, int age); }
詳しくはこちらを参照:https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html
Spring Data JPAが基本的に提供してくれるQuery Method機能
- 照会:
find...By
,read...By
,query...By
,get...By
...
にはクエリを説明する内容が入っても良い
- カウント:
count...By
- 返り値のタイプ :
long
- 返り値のタイプ :
- EXISTS:
exists...By
- 返り値のタイプ :
boolean
- 返り値のタイプ :
- 削除:
`delete...By`, `remove...By`
- 返り値のタイプ :
long
- 返り値のタイプ :
- DISTINCT:
`findDistinct`, `findUserDistinctBy`
- LIMIT:
`findFirst2`, `findFirst`, `findTop`, `findTop3`
JPA NamedQuery
JPAのNamedQueryを呼び出せる機能である。
まずNamedQueryを定義する
@Entity @NamedQuery( name="User.findByUsername", query="select u from User u where u.username = :username" ) public class Uesr { ... }
JPAを直接使いNamedQueryを呼び出す方法
public class UserRepository { public List<User> findByUsername(String username) { ... List<User> resultList = em.createNamedQuery("User.findByUsername", User.class) } }
Spring Data JPAでNamedQueryを呼び出す方法
@Query(name = "User.findByUsername")
List<User> findByUsername(@Param("username") String username);
@Query
を省略してメソッドの名前だけでNamedQueryを呼び出すこともできる。
public interface UserRepository extends JpaRepository<User, Long> { List<User> findByUsername(@Param("username") String username); }
- Spring Data JPAは定義した
ドメインクラス + .(period) + メソッド名前
を組み合わせNamedQueryを探して実行してくれる。 - もし実行するNamedQueryがないと上で説明した「**メソッド名前でクエリ作成**」戦略を使用する。
@Query, レポジトリメソッドにQueryを定義する
メソッドにJPQLクエリを作成
public interface UserRepository extends JpaRepository<User, Long> { @Query("select u from User u where u.username= :username and u.age = :age") List<User> findUser(@Param("username") String username, @Param("age") int age); }
@Query
アノテーションをしよする- Spring Data JPAが提供するのか要確認
- JPA NamedQueryみたいにアプリケーション実行時にSyntax Errorとかを検知できる。
- すごく良い長所である。
値、DTO照会
単純照会
@Query(select u.username from User u) List<User> findUsernameList();
- JPAの
@Embedded
がついたタイプもこの方式で照会できる。
DTOで直接照会
@Query("select new jp.co.tagbangers.UserDto(u.id, u.username, t.name) " + "from User u join u.team t") List<UserDto> findUserDto();
- DTOで直接照会するためにはJPAの
new
命令語を使う必要がある。 - コンストラクタが用意されている必要がある。
@Data public class UserDto { private Long id; private String username; private String teamName; public UserDto(Long id, String username, String teamName) { this.id = id; this.username = username; this.teamName = teamName; } }
Parameter Binding
- 順番方式
- 名前方式
select m from Member m where m.username = ?0 // 順番 select m from Member m where m.username = :name // 名前
なるべく名前方式を使うのをお勧めする。順番をミスして入れると大変なバグになる可能性が高い。
import org.springframework.data.repository.query.Param public interface UserRepository extends JpaRepository<User, Long> { @Query("select u from User u where u.username = :name") User findUser(@Param("name") String username); }
Collection Parameter Binding
in
をサポートする
@Query("select u from User u where u.username in :names") List<User> findByNames(@Param("names") List<String> names);
変換タイプ
Spring Data JPAは柔軟な変換タイプをサポートする
List<User> findByUsername(String name); // Collection
- 照会結果がない場合Empty Collectionを返す
User findByUsername(String name); // Select
- 照会結果がない場合
Null
を返す - 結果が2件以上だったら
javax.persistence.NonUniqueResultException
例外を発生する。
Optional<User> findByUsername(String name); // Optional