JPA 를 사용해서 연관관계를 매핑할 때 CASCADE, fetch(지연 로딩, 즉시 로딩) 등 다양한 용어가 나온다. 이들을 온전히 이해하지 못하면 데이터베이스에서 데이터를 가져올 때 날리는 쿼리문이 왜 이렇게 많이 날라가는지, 혹은 왜 쿼리문이 날라가지 않는지 등 이해가 되질 않을 것이다.
이러한 기본적인 용어들(CASCADE, 지연 로딩, 즉시 로딩)에 대해서 이해를 하기 위해서는 프록시에 대한 개념을 알고 있어야 한다.
public void printUserAndTeam(String memberId) {
Member member = em.find(Member.class, memberId);
Team team = member.getTeam();
System.out.println("회원 이름: " + member.getUsername());
System.out.println("소속팀: " + team.getName()); //데이터 실제 접근
}
위의 코드를 실행하면 em.find를 사용해서 영속성 컨테이너의 1차 캐시에 member, team에 대한 정보가 올라갈 것이다. 하지만 System.out.println("소속팀: " + team.getName());
코드를 주석 처리하면 team 은 1차 캐시에 저장되질 않는다.
그 이유는 Team team = member.getTeam();
에서 team 이 프록시 객체를 받고 있기 때문이다. 실제로 team.getName()
과 같은 team 에 데이터에 실질적인 접근을 할 때, 데이터베이스에 접근하여 값을 꺼내어 와서 1차 캐시에 저장한다.
그림으로 표현하면 위와 같다. 실질적으로 데이터에 접근하기 전까지는 team 객체는 Proxy 라는 가짜 객체를 담고 있다.
하지만 System.out.println("소속팀: " + team.getName());
이처럼 실제로 데이터에 접근을 시도한다면 아래 그림 처럼 동작하여 데이터 베이스에 접근한다. (MemberProxy -> TeamProxy / Member -> Team)