Spring/Spring Data JPA

[Spring Data JPA] 3-2. JPA Query Methods (2)

noahkim_ 2024. 8. 2. 13:37

4. Using @Query

  • repository에 JPQL 쿼리 직접 선언
  • 도메인 클래스로부터 쿼리 로직 분리

 

예제

더보기
public interface UserRepository extends JpaRepository<User, Long> {
    @Query("SELECT u FROM User u WHERE u.lastname = :lastname")
    List<User> findByLastname(@Param("lastname") String lastname);
}

 

@Param

  • query method's named parameter
  • parameter name 자동 탐지 제공 

예제

더보기
public interface UserRepository extends JpaRepository<User, Long> {

    @Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
    User findByLastnameOrFirstname(@Param("lastname") String lastname, @Param("firstname") String firstname);
}

 

설정) 컴파일러 플래그

더보기
tasks.withType(JavaCompile) {
    options.compilerArgs << '-parameters'
}
  • 해당 옵션으로 .class 파일에 파라미터 이름을 저장하도록 함
    • 메서드 파라미터 이름이 컴파일되면서 사라짐 (.class 파일의 파라미터 이름: arg0, arg1...)
  • Spring Data JPA 같은 프레임워크는 쿼리 메서드 매핑할 때, 파라미터 이름을 정확히 알 수 있게 됨

 

Applying a QueryRewriter

  • EntityManager에 보내기 전, 쿼리 수정을 담당함

예제

더보기
public interface MyRepository extends JpaRepository<User, Long> {

  @Query(value = "select original_user_alias.* from SD_USER original_user_alias",
         nativeQuery = true, queryRewriter = MyQueryRewriter.class)
  List<User> findByNativeQuery(String param);

  @Query(value = "select original_user_alias from User original_user_alias",
         queryRewriter = MyQueryRewriter.class)
  List<User> findByNonNativeQuery(String param);
}

public class MyQueryRewriter implements QueryRewriter {

  @Override
  public String rewrite(String query, Sort sort) {
    return query.replaceAll("original_user_alias", "rewritten_user_alias");
  }
}

 

Using Advanced LIKE Expressions

 

예제

더보기
public interface UserRepository extends JpaRepository<User, Long> {

  @Query("select u from User u where u.firstname like %?1")
  List<User> findByFirstnameEndsWith(String firstname);
}

 

 

Native Queries

예제

더보기
public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
  User findByEmailAddress(String emailAddress);
}

 

Paging

public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
         countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
         nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}
  • countQuery 정의 필요

 

5. Using SpEL Expressions

동적 쿼리 생성

  • #{entityName}: 도메인 클래스의 이름을 동적으로 쿼리에 삽입할 수 있음

 

예제

더보기
@MappedSuperclass
public abstract class AbstractMappedType {
  String attribute;
}

@Entity
public class ConcreteType extends AbstractMappedType {
  // 필드와 메서드 정의
}

@NoRepositoryBean
public interface MappedTypeRepository<T extends AbstractMappedType> extends Repository<T, Long> {
  @Query("select t from #{#entityName} t where t.attribute = ?1")
  List<T> findAllByAttribute(String attribute);
}

public interface ConcreteRepository extends MappedTypeRepository<ConcreteType> {
  // 구체적인 리포지토리 메서드 정의
}

 

동적 매개변수 조작

  • 매개변수: 이름 or 인덱스로 접근 가능

 

예제

더보기
@Query("select u from User u where u.firstname = ?1 and u.firstname = ?#{[0]} and u.emailAddress = ?#{principal.emailAddress}")
List<User> findByFirstnameAndCurrentUserWithCustomQuery(String firstname);


Like 조건

@Query("select u from User u where u.lastname like %:#{#lastname}% and u.lastname like %:lastname%")
List<User> findByLastnameWithSpelExpression(@Param("lastname") String lastname);
  • 와일드카드 추가 가능

 

Sanitizing

@Query("select u from User u where u.firstname like %?#{escape([0])}% escape ?#{escapeCharacter()}")
List<User> findContainingEscaped(String namePart);
  • escape(): '_', '%' 이스케이프 처리
  • escapeCharacter(): 이스케이프할 문자 설정

 


출처