개발천재

[Spring Boot] JPA @Query 사용하기 +메서드 이름 기반 쿼리 본문

개발 준비/Spring Boot

[Spring Boot] JPA @Query 사용하기 +메서드 이름 기반 쿼리

세리블리 2025. 2. 21. 21:54
반응형

@Query 이해하기

@Query는 Spring Data JPA에서 사용자 정의 쿼리를 작성할 때 사용하는 어노테이션으로, JPQL(엔티티 기반 쿼리)이나 Native SQL(DB 직접 쿼리)을 사용하여 복잡한 조건의 검색, JOIN, 서브쿼리 등을 자유롭게 구현할 수 있으며, 메서드 이름으로 작성하기 어려운 쿼리를 간결하게 표현하고 최적화할 때 유용하게 사용된다.

 


 

@Query를 사용하는 이유

복잡한 쿼리나 맞춤형 쿼리가 필요할 때, JPA 메서드 이름만으로는 부족할 때 사용한다. JPQL(Java Persistence Query Language)을 사용해서 엔티티 객체를 기반으로 쿼리를 작성할 수 있고, Native Query(순수 SQL)도 지원한다.

 

  • JPA 메서드 이름으로 만들기 어려운 경우
  • SQL 최적화가 필요한 경우
  • 복잡한 JOIN이나 조건이 많아질 때
  • 메서드 이름이 길어질 필요 없이 간단하게 쿼리 작성 가능
  • 복잡한 JOIN이나 서브쿼리도 자유롭게 작성할 수 있다.
  • JPQL과 Native SQL 모두 지원

 


 

 

@Query 사용 방법 1, JPQL로 작성하는 방법

@Query 안에 JPQL로 작성하는 방식이다.
:name은 파라미터 바인딩(값을 전달할 자리)하고 @Param으로 메서드 매개변수와 쿼리의 파라미터를 연결한다.

public interface MemberRepository extends JpaRepository<Member, Long> {
    @Query("SELECT m FROM Member m WHERE m.name = :name")
    List<Member> findByName(@Param("name") String name);
}

 

 

 

 

@Query 사용 방법 2, Native Query (SQL)

nativeQuery = true를 추가하면 SQL을 그대로 사용할 수 있다.
주의할 점은 테이블 이름과 컬럼명이 DB에 실제 존재하는 이름이어야 한다.

@Query(value = "SELECT * FROM member WHERE name = :name", nativeQuery = true)
List<Member> findByNameNative(@Param("name") String name);


@Query 예시
이름에 특정 키워드가 포함된 회원 검색하는 경우

@Query("SELECT m FROM Member m WHERE m.name LIKE %:keyword%")
List<Member> searchByName(@Param("keyword") String keyword);



2개 이상의 조건을 가진 쿼리일 경우

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

 

 

메서드 이름 기반 쿼리

메서드 이름 기반 쿼리(Method Query Derivation) 방식은 JPA가 메서드명을 분석하여 자동으로 SQL을 생성하는 방식이다. 특별한 쿼리가 필요 없다면 메서드 이름 기반 쿼리를 사용하는 것이 편리할 수 있다.

엔티티

@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Users {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 50)
    private String name;

    @Column(length = 50)
    private String email;

    @Column(length = 20)
    @Enumerated(EnumType.STRING)
    private Gender gender;

    @Column(length = 50)
    private String likeColor;

    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
}

 

 

레파지토리

@Repository
public interface UsersRepository extends JpaRepository<Users, Long> {
    // 이름으로 검색하는 기능
    List<Users> findByName(String name);

    // 색상 값을 받아서 그 중 처음으로 발견되는 3개의 데이터를 출력
    List<Users> findTop3ByLikeColor(String color);

    // 남자이면서 색상이 Yellow
    List<Users> findByGenderAndLikeColor(Gender gender, String color);

    // 범위 검색
    // 최근 7일 이내 자료를 읽어오고 싶을 때(오늘 빼고)
    List<Users> findByCreatedAtBetween(LocalDateTime start, LocalDateTime end);
}

 

 

내부적으로 변환되는 JPQL (예시)
위와 같이 자동으로 SQL이 생성된다.

SELECT * FROM users WHERE name = ?
SELECT * FROM users WHERE like_color = ? LIMIT 3
SELECT * FROM users WHERE gender = ? AND like_color = ?

 

 


 

 

쿼리 방식 비교

JPQL (Java Persistence Query Language)

  • 엔티티 기준으로 SQL과 비슷한 쿼리 작성
  • @Query("SELECT u FROM Users u WHERE u.name = :name")
  • 데이터베이스 독립적, SQL과 유사
  • 복잡한 SQL은 작성이 어려울 수도 있음

 

 

Native Query

  • 순수 SQL을 직접 실행
  • @Query(value = "SELECT * FROM users WHERE name = :name", nativeQuery = true)
  • 최적화된 SQL 사용 가능, 복잡한 쿼리 작성 가능
  • DB 종속적, 유지보수 어려움

 

 

메서드 이름 기반 쿼리 (Method Query Derivation)

  • 메서드명을 분석해 자동으로 SQL 생성
  • findByName(String name)
  • 간단한 CRUD에 적합, 유지보수 쉬움
  • 복잡한 쿼리는 어려움
반응형