프로젝트/HI-SERVER

JPA - findById

haema_ 2024. 3. 27. 17:41
728x90

3월달 업무 목표를 좀 일찍 끝내서, 오랜만에 개인 프로젝트 코드를 조금 작성해보았다.

업무에서 JSP, MyBatis 등을 다루다가 캠프에서 사용했었던 SpringBoot와 JPA를 오랜만에 사용해보니 감회가 새롭다.

JpaRepository

캠프에서는 MVC패턴으로 프로젝트를 작성할 때, JpaRepository를 extends한 repository interface를 만들어서 사용했었다.

 

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByLoginId(String loginId);
    Optional<User> findByUserId(Long userId);
}

 

이런 식으로 findBy@@(조건) 이라는 메서드를 interface에 작성하면, where절에 @@ = 조건 과 같은 방식으로 만들어준다.

 

예를들면, 위의 findByLoginId는 loginId를 매개변수로

SELECT * FROM user
WHERE login_id = 'loginId';

와 같은 형식으로 쿼리문을 만들어주는 것이다.

 

Entity의 변수명이나 찾고 싶은 조건은 비즈니스 상황에 따라 다양할 것이기 때문에, 그걸 고려했는지 확장시키기 아주 편리하게 돼있다.

 

JpaRepository에서의 Join

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long userId;
    @Column
    private String loginId;
    @Column
    private String nickname;
    @Column
    private String password;
    @Column
    private Long level;
    @Column
    private Long exp;
    @Column
    private Long gold;
    @ManyToOne
    @JoinColumn(name = "medal_id")
    private Medal medal;
}

 

User Entity가 이렇게 구성되어 있고,

User가 Medal정보를 일방적으로 조회할 예정이라 User쪽에서 Medal과 ManyToOne 단방향 관계를 맺었다.

 

위와 같은 Entity 상황에서,

JpaRepository의 상위interface인 CrudRepository의 findById와

내가 커스텀한 findByUserId가 다르게 동작한다는 것을 알게 되었다.

CrudRepository의 기본 findById(Long id)

 

 

 

두 가지 메서드 모두 Long타입의 userId를 기반으로 User를 조회하는 기능이다.

 

Case 1. Custom findBy~ Method

처음 코드를 작성할 땐 커스텀한 findByUserId로 조회했는데, Console의 Hibernate log를 확인해본 결과 쿼리가 2번 나가는 것을 확인했다.

1. User를 조회하기 위한 Select문과

2. Medal을 조회하기 위한 Select문이

각각 실행되었다.

 

Case 2. CrudRepository findById Method

동일한 상황에서, CrudRepository에서 기본 제공되는 findById를 사용했을 땐 Medal에 관한 정보를 left join해서 한 번에 가져오는 것을 확인할 수 있었다.

 

    @Test
    void userRepositoryTest() {
        System.out.println("========case 1=========");
        User user = userRepository.findByUserId(1L).orElse(null);
        System.out.println("========case 2=========");
        User user2 = userRepository.findById(2L).orElse(null);
    }

 

해당 테스트 코드를 기준으로, Console의 Hibernate log는 다음과 같다.

case 1 : custom method&nbsp; &nbsp;//&nbsp; &nbsp;case 2 : CrudRepository findById

 

fetchType을 EAGER로 설정해도 동일한 결과가 나온 것으로 봐선, custom method의 경우 join경로를 자동적으로 파악해주지는 못하는 것 같다.

 

 

 

결론

id기반 간단한 조회가 아니라면, 가급적이면 QueryDSL이나 JPQL 등을 사용하는 게 더 나은 것 같다.

아니면 설계적인 측면으로 접근해, 애초에 EAGER 방식으로 조회할만한 값이라면 굳이 Entity를 분리하지 않고 User 내에 나열하는 것도 방법일 것 같다.(비정규화)

user가 소유한 medal 변화에 따라서 update문이 더 복잡해지는 trade-off가 있겠지만.

 

단순한 발견이지만, 그래도 이런 게 하나씩 보이는 걸 보니 SQLD 공부하길 잘 했다는 생각이 든다.

반응형

'프로젝트 > HI-SERVER' 카테고리의 다른 글

JPA-EmbeddidId, 복합 키에 대한 이야기  (11) 2024.04.05
아이디 중복 검사  (0) 2023.12.16
개인 프로젝트) HI-SERVER 시작  (0) 2023.12.15