JPQL - JPQL 기본(5)
"인프런 - 자바 ORM 표준 JPA 프로그래밍 강의를 듣고 작성한 글 입니다."
www.inflearn.com/course/ORM-JPA-Basic#
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다. 초급 웹 개발 프로그
www.inflearn.com
조인
일반 SQL 과는 다르게 JPQL 은 Entity 를 중심으로 동작한다.
- 내부 조인과 외부 조인의 차이?
Member 데이터와 Team 데이터가 있을 때, 내부 조인의 경우 Team 데이터가 없으면 데이터 자체가 검색되지 않으나, 외부 조인의 경우 Team 데이터가 없더라도 Team 데이터는 null 로 표기한 채로 나머지 Member 데이터를 검색해서 반환해준다.
- 세타 조인?
연관관계가 없는 도메인 끼리 일단 테이블을 모두 불러온 다음 특정 조건을 가지고 비교를 해보고 싶을 때 활용할 수 있다.
SQL : select count(m) from Member m, Team t where m.username = t.name
-> 멤버 이름과 팀 이름이 똑같은 경우의 갯수를 센다, 사실상 있을수 없는 경우이다.
내부 조인(inner join)
아래의 코드를 살펴보자.
- JpaMain.java
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("member1");
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();
위와 같이 코드를 작성하고 애플리케이션을 실행하면 아래와 같은 Hibernate SQL 을 출력하는 것을 확인할 수 있다.
- Hibernate SQL
Hibernate:
/* insert jpql.Team
*/ insert
into
Team
(name, id)
values
(?, ?)
Hibernate:
/* insert jpql.Member
*/ insert
into
Member
(age, TEAM_ID, username, id)
values
(?, ?, ?, ?)
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: /* team 은 아직 사용하지도 않았는데 왜 select 쿼리가 나간것일까? */
select
team0_.id as id1_3_0_,
team0_.name as name2_3_0_
from
Team team0_
where
team0_.id=?
위의 Hibernate SQL 을 보면 내부 조인이 정상적으로 수행되는 것을 확인함과 동시에, team 객체를 아직 사용하지도 않았는데 갑자기 team 객체에 대해 select 문이 나온것을 확인할 수 있다.
이를 통해 주의해야 할 점으로 무엇을 알 수 있을까?
Member 와 Team 과 같은 다대일 연관관계 에서는 지연 로딩을 잘 활용해야 한다.
- Member.java
@ManyToOne(fetch = FetchType.LAZY) // 지연 로딩으로 연관관계를 설정해준다.
@JoinColumn(name = "TEAM_ID")
private Team team;
연관관계를 지연로딩으로 설정해준 후 다시 애플리케이션을 실행해보면 아래와 같이 Hibernate SQL 에서 team 객체에 대해 select 쿼리가 전달되지 않는 것을 확인할 수 있다.
- Hibernate SQL
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
/* 앞전과는 달리 team 객체에 대한 select 쿼리가 전달되지 않았다. */
* 내부 조인을 사용할 경우 inner 키워드는 생략할 수 있다.
하지만 유지 보수의 편의를 위해 되도록이면 생략하지 않고 작성해주는 것이 좋다.
외부 조인(outer join)
외부 조인을 JPQL 에서 구현하고 싶은 경우 JPQL 을 아래처럼 작성할 수 있다.
String query = "select m from Member m left outer join m.team t";
// 여기서 outer 키워드는 생략 가능하다.
- Hibernate SQL
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
세타 조인
세타조인의 경우 아래와 같이 JPQL 을 작성해줄 수 있다.
- JpaMain.java
String query = "select m from Member m, Team t where m.username = t.name";
- Hibernate SQL
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 /* 두 테이블을 크로스(곱해서) 해서 조인한다. */
join
Team team1_
where
member0_.username=team1_.name /* 이후 조건에 맞게 데이터를 검색한다. */
다음 글에서는 조인 ON 절 및 조인 대상 필터링에 대해 알아보자.