경로 표현식이란, ❗️(점)을 찍어 객체 그래프를 탐색하는 것❗️
➡️ 이와 같이 3가지로 구분되는데, 우리는 이 3가지를 구분할 줄 알아야 한다!!
m.username
@ManyToOne
, @OneToOne
, 대상이 엔티티(ex: m.team
)@OneToMany
, @ManyToMany
, 대상이 컬렉션(ex: m.orders
)📌 상태 필드 경로 탐색
- JPQL ➡️
select m.username, m.age from Member m
- SQL ➡️
select m.username, m.age from Member m
📌 단일 값 연관 경로 탐색
- JPQL ➡️
select o.member from Order o
- SQL ➡️
sselect m.* from Orders o inner join Member m on o.member_id = m.id
join
키워드 직접 사용select m from Member m join m.team t
select m.team from Member m
📌 묵시적 내부 조인은 편리해 보일 수는 있으나 조심해서 써야 함!
select o.member.team from Order o
➡️ 성공select t.members from Team
➡️ 성공select t.members.username from Team t
➡️ 실패select m.username from Team t join t.members m
➡️ 성공1️⃣ 항상 내부 조인
2️⃣ 컬렉션은 경로 탐색의 끝, 명시적 조인을 통해 별칭을 얻어야함
3️⃣ 경로 탐색은 주로 SELECT
, WHERE
절에서 사용하지만 묵시 적 조인으로 인해 SQL의 FROM(JOIN)
절에 영향을 줌
📌 실무 조언
- 가급적 묵시적 조인 대신에 명시적 조인 사용
- 조인은 SQL 튜닝에 중요 포인트
- 묵시적 조인은 조인이 일어나는 상황을 한눈에 파악하기 어려움
💡 페치 조인은 실무에서 정말 정말 중요하니! 잘 들어두기!!!!!!
select m from Member m join fetch m.team
SELECT M.*, T.* FROM MEMBER M INNER JOIN TEAM T ON M.TEAM_ID=T.ID
이와 같이 회원 정보와 팀 정보가 있는데, 나는 회원 정보와 팀 정보를 함께 뿌리기를 원한다면🤔?
이 때 페치조인을 하면,
JPA가 위와 같이 다섯개의 엔티티를 만들고 반환해준다(이 때 쿼리는 한방으로^^)!!
✔️ 페치 조인 사용 코드
String jpql = "select m from Member m join fetch m.team";
List<Member> members = em.createQuery(jpql, Member.class)
.getResultList();
for (Member member : members) {
// 페치 조인으로 회원과 팀을 함께 조회해서 지연 로딩X
System.out.println("username = " + member.getUsername() + ", " +
"teamName = " + member.getTeam().name());
}
➡️ username = 회원1, teamname = 팀A
➡️ username = 회원2, teamname = 팀A
➡️ username = 회원3, teamname = 팀B
select t from Team t join fetch t.members where t.name = ‘팀A'
SELECT T.*, M.* FROM TEAM T INNER JOIN MEMBER M ON T.ID=M.TEAM_ID WHERE T.NAME = '팀A'
✔️ 컬렉션 조인 사용 코드
String jpql = "select t from Team t join fetch t.members where t.name = '팀A'" List<Team> teams = em.createQuery(jpql, Team.class).getResultList();
for(Team team : teams) {
System.out.println("teamname = " + team.getName() + ", team = " + team);
for (Member member : team.getMembers()) {
// 페치 조인으로 팀과 회원을 함께 조회해서 지연 로딩 발생 안함
System.out.println(“-> username = " + member.getUsername()+ ", member = " + member);
}
}
📌 페치 조인과 일반 조회의 차이
1️⃣ JPQL은 결과를 반환할 때 연관관계 고려 X
➡️ SELECT 절에 지정한 엔티티만 조회함
➡️ 여기서는 팀 엔티티만 조회하고, 회원 엔티티는 조회 X
2️⃣ 페치 조인을 사용할 때만 연관된 엔티티도 함께 조회(=즉시 로딩)
3️⃣ 페치 조인은 객체 그래프를 SQL 한번에 조회하는 개념
1️⃣ JPQL
select t
from Team t join fetch t.members
where t.name = ‘팀A'
2️⃣ SQL
SELECT T.*, M.*
FROM TEAM T
INNER JOIN MEMBER M ON T.ID=M.TEAM_ID
WHERE T.NAME = '팀A'
setFirstResult
, setMaxResults
)를 사용할 수 없음@OneToMany(fetch = FetchType.LAZY)
➡️ 글로벌 로딩 전략
➡️ 이렇게 다형적으로 설계를 했다고 가정해보자! JPA는 몇 가지 특정 기능들을 제공하는데 하나씩 알아보자😉
1️⃣ JPQL
select i from Item i
where type(i) IN (Book, Movie)
2️⃣ SQL
select i from i
where i.DTYPE in (‘B’, ‘M’)
FROM
, WHERE
, SELECT
(하이버네이트 지원) 사용1️⃣ JPQL
select i from Item i
where treat(i as Book).auther = ‘kim’
2️⃣ SQL
select i.* from Item i
where i.DTYPE = ‘B’ and i.auther = ‘kim’
@Entity
@NamedQuery(
name = "Member.findByUsername",
query="select m from Member m where m.username = :username")
public class Member {
...
}
List<Member> resultList =
em.createNamedQuery("Member.findByUsername", Member.class)
.setParameter("username", "회원1")
.getResultList();
1️⃣ [META-INF/persistence.xml]
<persistence-unit name="jpabook" >
<mapping-file>META-INF/ormMember.xml</mapping-file>
2️⃣ [META-INF/ormMember.xml]
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm" version="2.1">
<named-query name="Member.findByUsername">
<query><![CDATA[
select m
from Member m
where m.username = :username
]]></query>
</named-query>
<named-query name="Member.count">
<query>select count(m) from Member m</query>
</named-query>
</entity-mappings>
🤔 : 재고가 10개 미만인 모든 상품의 가격을 10% 상승하려면 어떻게 하죠? JPA 변경 감지 기능으로 실행하려면 너무 많은 SQL이 실행되는데........
😀 : 그래 그런 걸 벌크 연산이라고 한단다. 소개해 주겠니^^?
1️⃣ 재고가 10개 미만인 상품을 리스트로 조회
2️⃣ 상품 엔티티의 가격을 10% 증가시킴
3️⃣ 트랜잭션 커밋 시점에 변경감지가 동작함
➡️ 변경된 데이터가 100건이라면 100번의 UPDATE SQL이 실행!
executeUpdate()
의 결과는 영향받은 엔티티 수 반환 UPDATE
, DELETE
지원INSERT
(insert into .. select, 하이버네이트 지원)명수아저씨 이제 본격적으로 프로젝트를 시작해봅시다^___^