인프런 커뮤니티 질문&답변

ymyun님의 프로필 이미지
ymyun

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

프록시

getReference 사용시 쿼리 관련

해결된 질문

작성

·

36

0

[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)

[질문 내용]

안녕하세요 강사님. 강의 수강 중에 질문 드려봅니다.

섹션9. 프록시 1편 11분경에, 코드를 그대로 따라 치고 실행해보았는데, 실제로 강의와 다르게 동작하는 거 같습니다.

try {
    Member member = new Member();
    member.setUsername("hello");

    em.persist(member);

    em.flush();
    em.clear();

    Member findMember = em.getReference(Member.class, member.getId());
    System.out.println("findMember.id = " + findMember.getId());
    System.out.println("findMember.username = " + findMember.getUsername());

    tx.commit();
} catch (Exception e) {
    tx.rollback();
} finally {
    em.close();
}

위와 같이 코드를 실행했는데요,

 

Hibernate: 
    select
        next value for Member_SEQ
Hibernate: 
    /* insert for
        hellojpa.Member */insert 
    into
        Member (USERNAME, MEMBER_ID) 
    values
        (?, ?)
Hibernate: 
    select
        m1_0.MEMBER_ID,
        t1_0.TEAM_ID,
        t1_0.name,
        m1_0.USERNAME 
    from
        Member m1_0 
    left join
        Team t1_0 
            on t1_0.TEAM_ID=m1_0.TEAM_ID 
    where
        m1_0.MEMBER_ID=?
findMember.id = 1
findMember.username = hello

콘솔에서는 이렇게 나옵니다.

 

findMember.id는 쿼리 실행 필요 없이 바로 출력 가능해야 할 거 같은데 쿼리가 먼저 실행되는 이유가 뭘까요?
(username을 꺼내쓰는 부분을 제거하고 실행해봐도 쿼리가 실행되고 id를 출력합니다.)

답변 2

0

ymyun님의 프로필 이미지
ymyun
질문자

이리저리 테스트를 해보다가 해결되었는데 이유가 궁금하여 추가 질문 드립니다../

Member findMember = em.getReference(Member.class, member.getId());
System.out.println("findMember.id = " + findMember.getId());

해당 구문으로 프록시 객체를 반환받고, getId()를 호출하면 데이터베이스 쿼리가 발생했었는데요,


Member 클래스를 살펴보던 중 id필드의 선언부와 Getter 메서드에서 변수 타입의 정의가 Long과 long으로 서로 다르게 설정되어 있었고, 이를 일치시키자 쿼리가 실행되던 문제가 해결되었습니다.

@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;

public long getId() { // long → Long으로 바꾸니 문제 해결
    return id;
}

 

질문

  1. 왜 필드와 Getter 메서드의 타입을 맞추는 것이 쿼리 실행 여부에 영향을 미치는지 궁금합니다.

  2. 프록시 객체의 초기화 동작과 관련이 있을까요? 아니면 Hibernate의 내부 동작과 관련된 사항인지 알고 싶습니다.

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. ymyun님

  • Hibernate는 엔티티 메타데이터를 생성할 때 필드 타입메서드 반환 타입을 함께 사용하여 매핑 정보를 구성합니다.

  • 필드와 Getter 메서드의 타입이 다르면, Hibernate는 이를 일치하지 않는 매핑으로 간주할 수 있습니다.

  • 이로 인해 Hibernate가 프록시 객체를 초기화하는 과정에서 적절히 데이터를 로드하지 못하거나, 필요 이상으로 쿼리를 트리거하는 상황이 발생할 수 있습니다.

감사합니다.

0

안녕하세요, 인프런 AI 인턴입니다.

ymyun님, 프록시 객체와 getReference의 동작에 대해 궁금증이 있으신 것 같습니다. getReference 메서드를 사용하면 실제 엔티티가 아닌 프록시 객체를 반환하여, 기본적으로는 실제 데이터베이스 조회를 지연하게 됩니다. 하지만 다음과 같은 경우에는 프록시 초기화가 발생하여 데이터베이스 조회가 발생할 수 있습니다.

  1. 프록시 초기화 상황: 프록시 객체에서 엔티티 속성에 접근하려고 할 때, 해당 속성이 아직 로드되지 않은 경우 실제 엔티티를 데이터베이스에서 조회해 옵니다. 여기서 findMember.getUsername()을 호출하기 때문에, Hibernate는 데이터베이스에서 실질적인 데이터를 조회하여 프록시를 초기화합니다.

  2. Identifier Direct Access: 프록시 객체는 식별자 값, 즉 ID는 이미 로드된 상태이므로 데이터베이스 조회 없이도 출력할 수 있지만, 실제 엔티티 데이터에 접근하려는 getUsername() 등의 메서드를 호출하면 이 시점에서 데이터베이스에서 실제 엔티티를 조회합니다. 프록시가 엔티티로 초기화되지 않은 경우에는 getId() 호출만으로도 프록시 초기화가 발생할 수 있습니다. 이는 JPA 구현체나 데이터베이스 설정에 따라 달라질 수 있습니다.

프록시 객체의 초기화와 관련하여 추가적인 정보를 담고 있는 JPA 프록시 객체 초기화 관련 질문 링크가 도움이 될 수 있습니다. 이 질문에서는 프록시 초기화와 데이터베이스 쿼리 실행의 맥락에 대한 자세한 설명을 제공하고 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

ymyun님의 프로필 이미지
ymyun

작성한 질문수

질문하기