SQL 조인과 실행되는 것은 똑같습니다.
차이는 엔티티를 중심으로 동작을 한다는 것입니다. 조금 객체 스타일로 조인 문법이 나갑니다.
내부 조인
SELECT m FROM Member m [INNER] JOIN m.team t
//회원과 연관된 팀을 t로 조인한다는 뜻입니다.
외부 조인
SELECT m FROM Member m LEFT [OUTER] JOIN m.team t
세타 조인
select count(m) from Member m, Team t where m.username = t.name
//모든 회원과 팀을 Cartesian 곱으로 불러와서 회원의 이름과 팀의 이름이 똑같은 애를 찾는다는 뜻입니다.
<aside> ❗ 회원과 팀이 연관관계가 있는 것이 맞습니다. 그런데 이 연관관계가 있다는 것을 좀 더 자세히 설명하면, 회원은 팀의 참조값을 가지고 있고, 반대로 팀도 회원의 참조값을 가지고 있습니다. 그래서 이 참조값을 통해서 연관관계가 이루어집니다.
이렇게 참조값을 가지고 있는 필드로 조인을 하는 것이 정상적인 조인 방법입니다.
그런데 회원의 이름과 팀의 이름은 서로 아무런 연관관계가 없는 필드입니다.
이렇게 아무런 연관관계가 없는 필드로 조인하는 방법을 세타 조인이라고 합니다.
예를 들어서 세타 조인을 사용하면 회원과 팀이 아니라, 팀 이름과 카테고리 이름이 같은 필드로도 조인이 가능하다고 이해하시면 됩니다.
</aside>
public class JpaMain_4 {
public static void main(String[] args) {
EntityManagerFactory enf = Persistence.createEntityManagerFactory("hello");
EntityManager em = enf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member();
member.setUsername("member1");
member.setAge(10);
member.changeTeam(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();**
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
enf.close();
}
}
inner join 쿼리가 나가는 것을 볼 수 있습니다.
<aside> ❗ 그런데 select 쿼리가 또 나갑니다??
지연 로딩에서 설명했지만 @ManyToOne
(일대다)를 사용할 때는 항상 fetch를 LAZY로 해야합니다.
</aside>
그래서 이제 조인이 되는 것을 알았으니 응용을 할 수 있습니다.