반응형
JPA 게시글은 대부분 인프런의 김영한님의 강의인 '자바 ORM 표준 JPA 프로그래밍' 기반으로 내용을 정리했습니다.
조인(JOIN)
내부 조인(INNER JOIN)
SELECT m FROM Member m [INNER] JOIN m.team t
JPQL 조인은 엔티티 중심으로 동작을 한다. Member와 연관있는 Team을 m.team과 같이 점(.)으로 표현하고, 별칭을 t로 준다.
참고로 내부 조인은 Member는 있는데 team 데이터가 없을 경우에 Member만 나온다.
// 실행 클래스
for(int i = 0; i < 100; i++) {
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("member" + i);
member.setAge(10);
member.setTeam(team);
em.persist(member);
}
em.flush();
em.clear();
String query = "select m from Member m inner join m.team t";
List<Member> result = em.createQuery(query, Member.class)
.getResultList();
Member와 Team의 양방향 연관관계를 위해 Member 클래스에 연관 관계 편의 메서드를 작성한다.
public void changeTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
그리고 실행해보자.
Hibernate:
/* select
m
from
Member m
inner join
m.team t */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as TEAM_ID4_0_,
member0_.username as username3_0_
from
Member member0_
inner join
Team team1_
on member0_.TEAM_ID=team1_.id
Hibernate:
select
team0_.id as id1_3_0_,
team0_.name as name2_3_0_
from
Team team0_
where
team0_.id=?
위와 같이 JOIN 외에 다른 SELECT 쿼리가 추가적으로 나간 것을 볼 수 있다. 이 부분은 지연 로딩 설정으로 해결할 수 있다.
//Member.class 중 일부
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "TEAM_ID")
private Team team;
// 출력 로그
Hibernate:
/* select
m
from
Member m
inner join
m.team t */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as TEAM_ID4_0_,
member0_.username as username3_0_
from
Member member0_
inner join
Team team1_
on member0_.TEAM_ID=team1_.id
참고로 JPQL의 inner 키워드는 생략이 가능하다.
String query = "select m from Member m join m.team t";
외부 조인(OUTER JOIN)
SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
외부조인은 Member만 있고 Team이 없는 경우에 Team을 다 NULL로 채워줘 Member와 Team이 같이 나오게 된다.
String query = "select m from Member m left outer join m.team t";
쿼리는 위의 예제에서 이 부분만 수정해주면 된다.
// 출력 로그
Hibernate:
/* select
m
from
Member m
left outer join
m.team t */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as TEAM_ID4_0_,
member0_.username as username3_0_
from
Member member0_
left outer join
Team team1_
on member0_.TEAM_ID=team1_.id
세타 조인
SELECT COUNT(m) FROM Member m, Team t WHERE m.username = t.name
세타 조인의 경우 Member와 Team을 카티션 곱으로하고 where절에 조건을 걸어주는 것이다.
세타 조인의 쿼리는 아래와 같이 from 절에 객체를 쭉 써주고 where절에 조건을 걸어주면 된다.
String query = "select m from Member m, Team t where m.username = t.name";
맞게 실행됐나를 확인하기 위해 이상하지만 예제를 조금 손 보고 실행해보자.
for(int i = 0; i < 100; i++) {
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("teamA"); //teamA로 변경
member.setAge(10);
member.setTeam(team);
em.persist(member);
}
em.flush();
em.clear();
String query = "select m from Member m, Team t where m.username = t.name";
List<Member> result = em.createQuery(query, Member.class)
.getResultList();
System.out.println("result.size() = " + result.size());
// 출력 로그
Hibernate:
/* select
m
from
Member m,
Team t
where
m.username = t.name */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as TEAM_ID4_0_,
member0_.username as username3_0_
from
Member member0_ cross // cross
join
Team team1_
where
member0_.username=team1_.name
result.size() = 10000
조인 - ON 절
- ON절을 활용한 조인(JPA 2.1부터 지원)
- 조인 대상 필터링
- 연관관계 없는 엔티티 외부 조인(하이버네이트 5.1부터)
조인 대상 필터링
- ex) 회원과 팀을 조인하면서, 팀 이름이 A인 팀만 조인
- JPQL
SELECT m, t FROM Member m LEFT JOIN m.team t on t.name = 'A'
- SQL
SELECT m.*, t.* FROM
Member m LEFT JOIN Team t ON m.TEAM_ID = t.id and t.name = 'A'
- 예제
String query = "select m from Member m left join m.team t on t.name = 'teamA'";
List<Member> result = em.createQuery(query, Member.class)
.getResultList();
// 출력 로그
Hibernate:
/* select
m
from
Member m
left join
m.team t
on t.name = 'teamA' */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as TEAM_ID4_0_,
member0_.username as username3_0_
from
Member member0_
left outer join
Team team1_
on member0_.TEAM_ID=team1_.id // **ON절
and (
team1_.name='teamA'
)
연관관계가 없는 엔티티 외부 조인
- ex) 회원의 이름과 팀의 이름이 같은 대상 외부 조인
- JPQL
SELECT m, t FROM
Member m LEFT JOIN Team t on m.username = t.name
- SQL
SELECT m.*, t.* FROM
Member m LEFT JOIN Team t ON m.username = t.name
- 예제
String query = "select m from Member m left join Team t on m.username = t.name";
List<Member> result = em.createQuery(query, Member.class)
.getResultList();
// 출력 로그
Hibernate:
/* select
m
from
Member m
left join
Team t
on m.username = t.name */ select
member0_.id as id1_0_,
member0_.age as age2_0_,
member0_.TEAM_ID as TEAM_ID4_0_,
member0_.username as username3_0_
from
Member member0_
left outer join
Team team1_
on ( // ** ON절
member0_.username=team1_.name
)
springboot 버전이 1.X 대면 하이버네이트 버전이 5.1이 아니라 안 될 수도 있다.
반응형