티스토리 뷰

dev_공부일지/spring data JPA

JPA NamedQuery

dev_0hoon 2024. 3. 5. 16:37
package study.datajpa.entity;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 기본생성자 만들기, 기본생성자는 JPA 스펙으로 private는 안된다.
@ToString(of = {"id", "username", "age"}) //toString을 만들 때에는 가급적이면 연관관계객체는 넣지 않는것이 좋다(서로 부르면서 무한루프 된다.)
@NamedQuery(
        name="Member.findByUsername",
        query="select m from Member m where m.username =: username"
)
public class Member {

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    private String username;
    private int age;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    private Team team;

    public Member(String username) { this.username = username; }

    public Member(String username, int age) {
        this.username = username;
        this.age = age;
    }
    public Member(String username, int age, Team team) {
        this.username = username;
        this.age = age;

        if(team != null) {
            changeTeam(team);
        }
    }

    public void changeTeam(Team team){
        this.team = team;
        team.getMembers().add(this);
    }
}

 

- 엔티티 상단에 NamedQuery를 작성해서 미리 쿼리를 만들 수 있다(JPQL).

 

사용하는 방식은 이렇다.

 

    public List<Member> findByusername(String username) {
        return em.createNamedQuery("Member.findByUsername", Member.class).setParameter("username", username).getResultList();
    }

미리 만들어 둔 NamedQuery를 name에 맞춰 작성한다.

 

이렇게 사용하는 방식도 있겠지만 JPARepository 인터페이스에서도 가능하다.

 

1 번 방법

public interface MemberRepository extends JpaRepository<Member,Long> {

    List<Member> findByUsernameAndAgeGreaterThan(String username, int age);

    List<Member> findTop3HelloBy();

    @Query(name="Member.findByUsername")
    List<Member> findByUsername(@Param("username")String username);
}

 

가장아래 코드를 보면 @Query 어노테이션의 name 값으로 엔티티에 미리 작성해둔 값을 가져올 수 있다.

@Param은 setParameter를 뜻하니 꼭 붙여줘야 한다.

- 참고: 이 때 메소드명은 중요하지 않다. 아무렇게 작명해도 괜찮다.

 

하지만 놀라운 방법도 있다.

 

2번 방법

public interface MemberRepository extends JpaRepository<Member,Long> {

    List<Member> findByUsernameAndAgeGreaterThan(String username, int age);

    List<Member> findTop3HelloBy();

    //@Query(name="Member.findByUsername")
    List<Member> findByUsername(@Param("username")String username);
}

 

이렇게 @Query를 지워도 작동한다. 그 이유는 extends를 할 때에 JpaRepository<엔티티명,아이디타입> 을 작성해줬을 때에 엔티티명을 기준으로 메소드명을 조합해 NamedQuery를 찾기 때문이다.

(예 : Member.findByUsername을 찾게 된다.)

 

하지만 실무에서는 사실 이 방법은 잘 사용하지 않는다. 더 막강한 기능이 있기 때문이다.

 

NamedQuery의 큰 장점

- namedQuery는 쿼리가 잘 못 되었을 경우 컴파일 시점에서 오류가 뜬다. 그러므로 개발자가 가장 먼저 오류를 잡을 수 있는 기회를 제공한다.

 

 

3번 방법 (막강한 방법)

public interface MemberRepository extends JpaRepository<Member,Long> {

    List<Member> findByUsernameAndAgeGreaterThan(String username, int age);

    List<Member> findTop3HelloBy();

    //@Query(name="Member.findByUsername")
    List<Member> findByUsername(@Param("username")String username);

    @Query("select m from Member m where m.username = :username and m.age = :age")
    List<Member> findUser(@Param("username")String username, @Param("age")int age);
}

 

이렇게 인터페이스 메소드 위에 직접 JPQL 작성이 가능하다.

- 이 경우에도 쿼리가 틀렸을 경우 오류가 난다. 즉 개발단계에서 개발자가 미리 보정이 가능하다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함