BackEnd/JPA

[JPA] 연관관계 매핑 : 기본 (2)

JJangGu 2022. 5. 8. 22:58

지난 글에 이어서 연관관계 매핑 기본이라고 생각되는 부분을 이어서 작성하겠습니다. 이번에는 연관관계를 매핑한 엔티티를 어떻게 저장,수정하는지 알아보려고 합니다. 

 

public void save() {
	
    Team team1 = new Team("team1", "팀 1");
    em.persist(team1);
    
    Member member1 = new Member("member1", "회원 1");
    member1.setTeam(team1);
    em.persist(member1);
    
    Member member2 = new Member("member2", "회원 2");
    member2.setTeam(team1);
    em.persist(member2);
}

위의 코드를 보겠습니다. 코드를 보면 두개의 Member 엔티티에 Team 하나를 매핑해준 모습을 볼 수 있습니다. 여기서 주의할 점은 JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속상태여야 한다는 것 입니다. 

 

member.setTeam(team1); 을 통해서 회원 엔티티가 팀 엔티티를 참조하도록 하였습니다. JPA 는 참조한 팀의 식별자를 외래키로 사용해서 적절한 등록 쿼리를 생성한다. 

 

INSERT INTO TEAM (TEAM_ID, NAME) VALUES ('team1', '팀 1');
INSERT INTO MEMBER (MEMBER_ID, NAME, TEAM_ID) VALUES ('member1', '회원 1', 'team1');
INSERT INTO MEMBER (MEMBER_ID, NAME, TEAM_ID) VALUES ('member2', '회원 2', 'team1');

위와 같은 쿼리가 작성되어 우리가 원하는대로 데이터가 들어가게 됩니다. 이렇게 저장하는 것을 봤습니다. 다음은 조회하는 것을 보겠습니다.

 

연관관계가 있는 엔티티를 조회하는 방법은 크게 2가지입니다.

 

  • 객체 그래프 탐색
  • 객체지향 쿼리 사용 (JPQL)

이렇게 두가지인데요, 차례대로 보겠습니다.

 

Member member = em.find(Member.class, "member1");
Team team = member.getTeam();

이렇게 객체를 통해 연관된 엔티티를 조회하는 것을 객체 그래프 탐색이라고 합니다. 물론 프록시와 지연로딩 등 이 지점에서 더 공부하고 알아야 할 것이 있지만, 이번에는 기본편으로 쓴 만큼 소개정도만 하고 넘어가겠습니다. 

 

그리고 JPQL 을 이용하여 검색하는 방법이 있는데요, JPQL은 Java Persistence Query Language 의 약자입니다. 

 

private static void queryLogicJoin(EntityManager em) {
	
    String jpql = "select m from Member m join m.team t where t.name=:teamName";
    
    List<Member> resultList = em.createQuery(jpql, Member.class)
    	.setParameter("teamName", "팀 1");
        .getResultList();
}

 JPQL 로 조회를 해본 코드입니다. jpql 을 보면 SQL 과 유사한 것을 볼 수 있습니다. :teamName 에 파라미터를 바인딩 받아 쿼리를 실행하는 것이죠. 실제 쿼리와는 차이가 좀 있지만 이것도 좀 더 나중에 자세히 다뤄보겠습니다. 

 

JPQL 을 잘 알아야한다고 생각이 드는 이유가 뒤에서 다룰 Criteria 와 QueryDSL 때문이기도 한데, 저는 특히 실무에서 복잡한 쿼리가 필요한 경우에는 QueryDSL을 많이 활용하였습니다. 또한 JPQL 로 해결을 못하는 쿼리는 네이티브 쿼리를 사용하기도 합니다. 이는 후에 JPQL에 대해서 자세히 다룰때 모두 이야기 해보겠습니다. 

 

이제 마무리로 연관관계를 수정하거나 제거하는 것을 보겠습니다. 

 

private static void updateRealation(EntityManager em) {
	
    Team team2 = new Team("team2", "팀 2");
    em.persist(team2);
    
    Member member = em.find(Member.class, "member1");
    member.setTeam(team2);
}

수정은 setTeam(team2); 로 새로운 팀을 setter 로 넣어주기만 하였는데요, update에 대한것은 영속 컨텍스트에 대한 설명에서 변경 감지에 대해 이야기 했던 것이 있습니다. 엔티티의 값을 변경해두었다면 트랜잭션 커밋시 플러시가 일어날때 변경 감지 기능이 동작하며 변경 사항을 데이터베이스에 기록할 것 입니다. 

 

연관관계를 삭제할 때는 setTeam(null); 로 연관관계를 제거할 수 있습니다. 만약 연관된 엔티티 team 을 삭제하고 싶다면 연관관계를 모두 끊어내고 em.remove(team) 로 삭제하면 됩니다. 

 

여기까지가 연관관계의 가장 기본기라고 생각을 합니다. 바로 다음부터 "연관관계의 주인" 과 "양방향 연관관계" 를 설명할 텐데, 여기까지도 기본으로 볼까 고민을 좀 했습니다만 한번 끊어가는게 좋을 것 같아 기본편은 여기서 마무리하고 "연관관계의 주인"부터 다음 글에 쓰도록 하겠습니다.