즉, 프록시는 “껍데기”이고, 그 안에 실제 객체를 호출한다.
instance of
를 사용하자.==
나 .equals()
로 비교하면 실패할 수 있다.File file = entityManager.getReference(File.class, 1L); // 프록시 객체
file instanceof File; // ✅ true
file.getClass() == File.class; // ❌ false
File file1 = entityManager.find(File.class, 1L); // 실제 객체
// 프록시 객체로 가져오기 위해 "getReference"를 사용했지만, 실제 객체가 반환됨
File file2 = entityManager.getReference(File.class, 1L);
file1 == file2; // ✅ true
.find()
.getReference()
Member member = new Member();
member.setName("palmer");
entityManager.persist(member); // 영속 상태 및 Insert 쿼리 날림
Team team = new Team();
team.setName("chelsea");
entityManager.persist(team); // 영속 상태 및 Insert 쿼리 날림
entityManager.clear(); // 영속성 컨텍스트 초기화
Member proxy = entityManager.getReference(Member.class, member.getId());
System.out.println(proxy.getClass()); // 프록시 객체
Member member = new Member();
member.setName("palmer");
entityManager.persist(member); // 영속 상태 및 Insert 쿼리 날림
Team team = new Team();
team.setName("chelsea");
entityManager.persist(team); // 영속 상태 및 Insert 쿼리 날림
entityManager.clear(); // 영속성 컨텍스트 초기화
Member proxyMember = entityManager.getReference(Member.class, member.getId());
proxyMember.getName(); // 이 때, 진짜 객체의 값을 조회하여 반환한다.
System.out.println(proxy.getClass()); // 프록시 객체는 바뀌지 않는다.
proxyMember 생성 → proxy.getName() 호출
→ 프록시 초기화 과정에서 영속성 컨텍스트가 DB 접근
→ 실제 Member 객체 로딩 및 영속성 컨텍스트 재등록
→ 프록시가 실제 Member 객체를 참조하게 됨 (target)
→ 실제 객체의 getName() 결과 반환
지연로딩으로 세팅하면 연관관계를 프록시 객체로 가져온다.
실제로 사용하는 순간에 쿼리를 날려 프록시 객체에 진짜 객체를 연결해준다.
연관관계가 자주 함께 사용되는 경우에 사용한다.
쿼리를 한번만 날려 한꺼번에 가져올 수 있기 때문에 성능상 유리할 수 있다.
JPA는 최대한 조인을 통해 한꺼번에 가져오려고 하는 경향이 있다.
@ManyToOne
, @OneToOne
의 기본 설정은 즉시로딩이다.
즉시로딩을 적용하면 예상치 못한 쿼리가 날라갈 수 있기 때문에
주의해서 사용해야 한다.
Team teamA = new Team();
teamA.setName("chelsea");
entityManager.persist(teamA); // teamA
Team teamB = new Team();
teamB.setName("liverpool");
entityManager.persist(teamB); // team B
Member memberA = new Member();
memberA.setName("palmer");
memberA.setTeam(teamA);
entityManager.persist(memberA); // memberA
Member memberB = new Member();
memberB.setName("salah");
memberB.setTeam(teamB);
entityManager.persist(memberB); // memberB
entityManager.clear(); // 영속성 컨텍스트 초기화
// N+1 문제 발생하는 쿼리
List<Member> result = entityManager
.createQuery("select m from Member m", Member.class)
.getResultList();
@ManyToOne
설정을 했다.Member
에 관한 SQL을 만들 때,Member
객체에 Team
이 즉시로딩 설정이 되어있는 것을 보고,Team
을 조회하게 된다.@EntityGraph
, @BatchSize
, fetch join
등으로 해결할 수 있다.김영한 자바 ORM 표준 JPA 프로그래밍