
안녕하세요
저번에 Fetch조인과 일반 조인 차이점에 대해 포스팅했었는데
그 궁금증의 시작
"왜 Fetch Join 대상에 alias를 사용하면 안될까?"
대해 포스팅 해보겠습니다.

일단 이유는 JPA의 엔티티 객체 그래프는 DB와 데이터 일관성을 유지해야 하기 때문입니다.
뭔 소리냐고요?
(저도 처음 듣고 엥스바리 했습니다.)
예시를 들어 보겠습니다.
(저는 이번에 공부하면서 영속성 컨텍스트라는 개념이 얼마나 중요한지 ㅋ
싸악 알게 되었습니다)
먼저 예시 데이터를 보겠습니다.

Team1 - 유저1, 유저2
Team2 - 유저3
인 상황입니다.
JPQL
// 1. 팀을 페치조회하는데 유저이름으로 필터링
public List<Team> findByMemberName(String memberNm){
return em.createQuery("select t from Team t join fetch t.members m"+
" where m.name = memberNm", Team.class)
.setParameter("memberNm",memberNm)
.getResultList();
}
// 2. teamId로 team을 가져옴
public List<Team> findByTeamId(Long teamId){
return em.createQuery("select t from Team t where t.id =teamId", Team.class)
.setParameter("teamId", teamId)
.getResultList();
}
첫 번째 JPQL을 보면 Team을 조회하면서 fetch조인으로 연관된 Member 엔티티를 모두 가져오는데 별칭을 사용해 memberNm으로 필터링해서 가져옵니다. (Team1 {members=['유저1']} )
두 번째 JPQL은 단순히 teamId로 Team을 가져옵니다.
그럼 이 테스트 코드를 보겠습니다.
테스트 코드
@Test
public void 페치조인_데이터_일관성_확인() throws Exception{
List<Team> teamsWithUser1 = memberRepository.findByMemberName("유저1");
List<Team> fullTeamById = memberRepository.findByTeamId(1L);
for (Team team:teamsWithUser1) {
for (Member member:team.getMembers()) {
System.out.println("teamsWithUser1.member = " + member.getName());
}
}
for (Team team2:fullTeamById) {
for (Member member:team2.getMembers()) {
System.out.println("fullTeamById.member = " + member.getName());
}
}
}
단순히 위에 JPQL을 호출해서 해당 팀에 멤버를 조회하는 테스트 코드입니다.
결과가 예상 가능하신가요?
첫 번째 teamWithUser1에서는 유저1 / 두 번째 fullTeamById 에서는 teamId 1인 팀에 멤버를 가져오니까 유저1, 유저2 이렇게 조회될까요?
테스트 결과
select
team0_.team_id as team_id1_7_0_,
members1_.member_id as member_i1_4_1_,
team0_.name as name2_7_0_,
members1_.city as city2_4_1_,
members1_.street as street3_4_1_,
members1_.zipcode as zipcode4_4_1_,
members1_.name as name5_4_1_,
members1_.team_team_id as team_tea6_4_1_,
members1_.team_team_id as team_tea6_4_0__,
members1_.member_id as member_i1_4_0__
from
team team0_
inner join
member members1_
on team0_.team_id=members1_.team_team_id
where
members1_.name='유저1'
2025-05-13 15:30:15.556 DEBUG 34196 --- [ Test worker] org.hibernate.SQL :
select
team0_.team_id as team_id1_7_,
team0_.name as name2_7_
from
team team0_
where
team0_.team_id='1'
team.member = 유저1
team2.member = 유저1
놀랍게도 teamId 1인 Team을 조회한 Team1의 멤버는 유저1만 나옵니다.
왜일까요????
영속성 컨텍스트를 기억하시나요?

조회된 엔티티는 영속성 컨텍스트 1차 캐시에 들어가게 되고 식별자는 id값입니다.
그래서 처음 조회한 필터링된 Team1이 1차 캐시에
id = 1 , Entity = Team {Memebers=['유저1']} 이러한 형태로 들어가게 됩니다.
그다음 teamId 값으로 Team을 조회했을 때 db에 접근하기 전에 1차 캐시를 먼저 들려 id를 확인해서 있으니
기대값과는 다른 멤버를 반환하게 됩니다.
이렇게 데이터 일관성이 깨지게 됩니다.
그래서 페치 조인은 연관 엔티티를 모두를 가져오는 기능에 맞춰서 사용해야 됩니다.

정말 이거 공부하면서 좀 개념 틀이 잡힌 느낌이 들었습니다 ㅋ
여하튼 틀린 부분이나 궁금한 부분 있으시면 댓글 주시길 바랍니다~!
감사합니다~!









