<aside> ❗

경로 표현식

SELECT m.username -> 상태필드
	FROM Member m
		JOIN m.team t -> 단일 값 연관 필드
		JOIN m.orders o -> 컬렉션 값 연관필드 
WHERE t.name = '팀A'

</aside>

<aside> ❗

경로 표현식 용어 정리

3가지 경로 표현식 존재 - 상태필드, 단일 값 연관 필드, 컬렉션 값 연관 필드 → 내부적으로 동작하는 방식이 달라 결과가 달라짐

<aside> ❗

경로 표현식 특징

// m.username은 상태 필드 
// 경로 탐색의 끝 
String query = "SELECT m.username FROM Member m";
// 단일 값 연관 필드 
// 객체 그래프 탐색 가능 
String query = "SELECT m.team FROM Member m";
**// Member와 Team을 조회해서 Team 정보를 가져온다.** 

// 상태필드가 되어 경로 탐색 끝
String query = "SELECT m.team.name FROM Member m";
// t.members 이후 탐색 불가 
// t.members.size는 가능 
String query = "SELECT t.members FROM Team t";

// 명시적 조인을 사용해야 함 
// 명시적 조인을 사용하면 별칭을 얻을 수 있다.
**// 별칭을 가지고 탐색 가능** 
String query = "SELECT m FROM Team t JOIN t.members m";

**** 묵시적 내부 조인이 발생하게 쿼리를 작성하면 안 된다.**** → 성능에 영향을 주고 쿼리 튜닝하기도 어렵다. (운영하기 어려움) → JPQL과 SQL을 최대한 맞춰서 짠다.

실무에서는 묵시적 조인을 절대 사용하지 말고 **명시적 조인을 사용해라쿼리 튜닝하기도 쉬움**

</aside>

<aside> ❗

상태 필드 경로 탐색

<aside> ❗

단일 값 연관 경로 탐색

<aside> ❗

명시적 조인, 묵시적 조인

<aside> ❗

경로 탐색을 사용한 묵시적 조인 시 주의사항

<aside> ❗

실무 조언

<aside> ❗

페치 조인 (fetch join) - 매 우 중 요

<aside> ❗

엔티티 페치 조인

[JPQL]

// m만 조회했는데, m과 t의 데이터를 다 가져온다.
SELECT m FROM Member m JOIN FETCH m.team

[SQL]

SELECT M.*, T.* FROM MEMBER M
INNER JOIN TEAM T ON M.TEAM_ID = T.ID

image.png

// 최악의 경우 N + 1 번 쿼리를 보냄 
// 회원들 조회 (DB에서 회원들 정보 조회) 1
// 회원1 (DB에서 팀 A조회)
// 회원2 (1차 캐시에서 팀 A조회) 2
// 회원3 (DB에서 팀 B조회) 3
"SELECT m FROM Member m";

[N+1]

페치 조인 사용 코드

// Member를 조회하는데, 연관된 팀을 한 번에 조인해서 가져옴
String jpql = "SELECT m FROM Member m JOIN FETCH m.team";

List<Member> members = em.createQuery(jpql, Member.class)
	.getResultList();

// 패치 조인을 사용하면 지연로딩을 걸어도 프록시 클래스가 아님 
// **영속성 컨텍스트에 실제 엔티티가 올라가 있음 (프록시 X), 즉 실제 데이터가 다 들어가 있음** 
for(Member member : members){
	System.out.println("username = " + member.getUsername() + ", " +
							"testName = " + member.getTeam().name());
}
/*
select
            m1_0.MEMBER_ID,
            m1_0.city,
            m1_0.street,
            m1_0.zipcode,
            m1_0.age,
            t1_0.TEAM_ID,
            t1_0.name,
            m1_0.type,
            m1_0.username 
        from
            Member m1_0 
        join
            Team t1_0 
                on t1_0.TEAM_ID=m1_0.TEAM_ID
*/
/*
username = 회원1, teamname = 팀A
username = 회원2, teamname = 팀A
username = 회원3, teamname = 팀B
*/

[참고]