회원과 크루 예시를 그대로 가져가겠다.
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name="crew_id")
private Crew crew;
...
}
@Entity
public class Crew {
@Id @GeneratedValue
private Long id; //crewId
private String name;
@OneToMany(mappedBy="crew") // Crew입장에서 Member는 1:N
private List<Member> members = new ArrayList<>();
...
}
Member를 조회할 때 Crew도 함께 조회해야 할까?
Member member = em.find(Member.class, 1L);
printMember(member); // 1. Member만 조회
printMemberAndCrew(member); // 2. Member와 Crew를 함께 조회
만약 Member정보만 출력하고싶고 Crew는 출력하고싶지 않는 경우도 있을 것이다.
사용하지도 않는 정보인 Crew 정보까지 땡겨온다면 뭔가 깔끔하지 않다.
어떤 경우엔 Member와 Crew를 함께 가져오고싶고, 어떤 경우엔 Member만 가져오고싶을 땐 어떻게 해야할까?
JPA는 이러한 문제를 지연 로딩, 프록시 등을 통해 해결한다.
Member member = new Member();
member.setUsername("hello");
em.persist(member);
em.flush();
em.clear();
Member findMember = em.getReference(Member.class, member.getId());
tx.commit();
실행 결과
/* insert hellojpa.Member
*/ insert
into
Member
(MEMBER_ID, createBy, createdDate, lastModifiedBy, lastModifiedDate, city, street, zipcode, team_TEAM_ID, name)
values
(null, ?, ?, ?, ?, ?, ?, ?, ?, ?)
10월 04, 2023 1:32:44 오전 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop
INFO: HHH10001008: Cleaning up connection pool [jdbc:h2:tcp://localhost/~/hellojpa;MODE=MYSQL]
Process finished with exit code 0
...
Member findMember = em.getReference(Member.class, member.getId());
System.out.println("findMember.getClass() = " + findMember.getClass());
System.out.println("findMember.getUsername() = " + findMember.getUsername());
tx.commit();
findMember.getClass() = class hellojpa.Member$HibernateProxy$2gyJwktl
Hibernate:
select
member0_.MEMBER_ID as MEMBER_I1_4_0_,
member0_.createBy as createBy2_4_0_,
member0_.createdDate as createdD3_4_0_,
member0_.lastModifiedBy as lastModi4_4_0_,
member0_.lastModifiedDate as lastModi5_4_0_,
member0_.city as city6_4_0_,
member0_.street as street7_4_0_,
member0_.zipcode as zipcode8_4_0_,
member0_.team_TEAM_ID as team_TE10_4_0_,
member0_.name as name9_4_0_
from
Member member0_
where
member0_.MEMBER_ID=?
findMember.getUsername() = hello
프록시 인스턴스 초기화 여부
entitiyManagerfactory.getPersistenceUnitUtil.isLoaded(Object entity)
프록시 클래스 확인 방법
entity.getClass().getName()
프록시 강제 초기화
org.hibernate.Hibernate.initialize(entity)
약간 헷갈린다면 직접 em.find(...), em.getReference(...)해서 값을 가져온 다음 타입 비교를 해보자.
프록시에 대해 알아보았고 프록시에 대한 이해가 있어야 즉시 로딩, 지연 로딩을 깊이 이해할 수 있다.
맨 위에서 언급한 Member를 조회할 때 Crew도 함꼐 조회해야하는지에 대한 질문의 답을 이제 알아보자.
@Entity
public class Member extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="crew_id")
private Crew crew;
}
@Entity
public class Member extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name="crew_id")
private Crew crew;
}
직접 즉시 로딩, 지연 로딩을 해보면서 나가는 쿼리문을 눈으로 보는 것을 추천한다.
@Entity
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany
(mappedBy = "parent",
cascade = CascadeType.ALL)
private List<Child> childList = new ArrayList<>();
...
}
@Entity
public class Child{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "PARENT_ID")
private Parent parent;
...
}
Child ch1 = new Child();
Child ch2 = new Child();
Parent parent = new Parent();
parent.addChild(ch1); // 연관관계 편의 메서드
parent.addChild(ch2); // 연관관계 편의 메서드
em.persist(parent);
tx.commit();
@Entity
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany
(mappedBy = "parent",
cascade = CascadeType.ALL,
orphanRemoval = true) //이 부분
private List<Child> childList = new ArrayList<>();
...
}
@Entity
public class Child{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "PARENT_ID")
private Parent parent;
...
}
자바 ORM 표준 JPA 프로그래밍-기본편을 학습하면서 정리한 블로그입니다.