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

토마토님의 프로필 이미지

작성한 질문수

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

단방향 연관관계

영속 상태에서 값을 가져오는 것에 대해 질문 드립니다.

24.07.08 00:33 작성

·

98

0

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

[질문 내용]

em.flush() 와 em.clear() 를 하지 않은 영속 상태에서 1차 캐시로부터 가져온 값인 members 에 대해 질문이 있습니다.

아래 코드 중 주석으로 '궁금한 부분'이라 표시한 것 처럼 출력하고자 할 때, 제 예상으로는 1차 캐시에서 members 도 무사히 가져왔으니(확인 완료) 가져온 값을 출력만 하면 될 것 같았습니다. 그러나 이후 실행 결과 출력 되지 않았습니다.

이유를 알려주시면 감사할 것 같습니다!

<코드>

package hellojpa;

import jakarta.persistence.*;

import java.util.List;

public class JpaMain {

    public static void main(String[] args) {

        // 문제 없이 돌아가는 지 확인
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

        // 쿼리를 한 번 날리고 종료되는 일관적인 단위를 할 때마다, 이 EntityManager 를 꼭 생성해야 한다.
        EntityManager em = emf.createEntityManager();

        // JPA 에서 데이터를 변경하는 모든 작업은 꼭 Transaction 안에서 작업을 해야 한다.
        EntityTransaction tx = em.getTransaction();
        tx.begin();         // 트랜잭션 시작

        // 실제 code를 작성한다.
        try {
            // 팀 등록
            Team team = new Team();
            team.setName("TeamA");
            em.persist(team);

            // 회원 등록
            Member member = new Member();
            member.setUsername("userA");
            member.setTeam(team);
            em.persist(member); // JPA 저장

            Member findMember = em.find(Member.class, member.getId());

            Team findTeam = findMember.getTeam();
            System.out.println("findTeam = " + findTeam.getName());

            List<Member> members = findMember.getTeam().getMembers();

            System.out.println("===============");

            // 궁금한 부분!!!
            // em.clear()~ 등을 하지 않은 영속 상태라고 가정할 때(1차 캐시에서 값을 가져옴)
            // team 을 통해 members 목록도 불러올 수 있는데, 왜 아래의 iterator 는 작동하지 않을까?
            for (Member m : members) {
                System.out.println("통과");
                System.out.println("member1 = " + m.getUsername());
            }

            System.out.println("===============");


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

        emf.close();
    }
}

<실행 결과>

image.png

답변 2

2

David님의 프로필 이미지

2024. 07. 08. 19:44

안녕하세요. 토마토님, 공식 서포터즈 David입니다.

Team 생성: members는 비어있는 상태. null이 아닙니다.

Member 생성, setTeam(): Member를 통해 팀을 호출 가능한 상태

DB: 아무것도 반영되어 있지 않음.

이 상태에서 Team을 통해 Team이 가진 members를 호출해도 아무것도 없습니다.

members에 값이 채워지려면 DB를 통해 위의 사항들이 반영된 다음, DB에서 Team을 조회함으로 1차 캐시에는 members 값이 채워진 Team이 저장되게 됩니다.

이런 상황을 방지하려고 연관관계 편의 메서드를 사용하게 됩니다. 이 부분은 양방향 연관관계와 연관관계의 주인 2 - 주의점, 정리편을 참고해 주세요.

감사합니다.

0

인프런 AI 인턴님의 프로필 이미지

2024. 07. 08. 00:36

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

토마토님의 질문과 유사한 문제로 영속 상태에서 em.flush()em.clear() 를 하지 않았을 때의 동작에 대해 궁금해 하신 경우가 있었습니다.

질문자님이 관심을 가질만한 내용으로는, 영속 상태에서의 동작, 특히 em.flush()em.clear()를 명시적으로 호출하지 않았을 때 1차 캐시와 데이터베이스 사이의 상호 작용에 대한 부분입니다.

이와 관련하여, 영속 상태에서 엔티티를 관리하고 1차 캐시를 활용하는 방법에 대해 설명한 기존 질문의 답변을 참고하시는 것이 좋을 것 같습니다:

  • 질문 제목: em.flush() & em.clear() 제가 이해하고 있는게 맞나요?
  • 답변 내용: em.flush()는 영속성 컨텍스트에 있는 변경 내용을 데이터베이스에 반영하며, em.clear()는 영속성 컨텍스트를 초기화합니다. 이 과정에서 영속 상태의 엔티티들이 어떻게 관리되고 데이터베이스와 어떤 상호 작용을 하는지에 대한 설명이 포함되어 있습니다.

주로, em.flush()는 영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하지만, 영속성 컨텍스트를 비우지는 않습니다. 따라서 1차 캐시의 내용은 그대로 유지됩니다. 반면, em.clear()를 호출하면 영속성 컨텍스트를 초기화하여 모든 엔티티를 준영속 상태로 만듭니다.

토마토님의 질문에서 보여주신 코드 상황에서 members 리스트가 예상대로 출력되지 않는 경우, 이는 연관 관계에 있는 엔티티들이 영속 상태에서 어떻게 처리되는지를 보는 것이 중요합니다. 특히, 지연 로딩과 즉시 로딩의 차이, 그리고 영속성 컨텍스트가 어떻게 엔티티의 상태를 관리하는지에 대한 부분을 이해하는 것이 핵심입니다.

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