11. 연관관계 매핑 기초(2)

11. 연관관계 매핑 기초(2)

2. 연관관계 사용

연관관계를 등록, 수정, 삭제, 조회하는 예제를 통해 연관관계를 어떻게 사용하는지 알아보자.

1. 저장

연관관계를 매핑한 엔티티를 어떻게 저장하는지 아래 예제로 알아보자.

public void testSave() {

    // 팀1 저장
    Team team1 = new Team("team1", "팀1");
    em.persist(team1);
    
    // 회원1 저장
    Member member1 = new Member("member1", "회원1");
    member1.setTeam(team1);  // 연관관계 설정 member1 -> team1
    em.persist(member1);
    
    // 회원2 저장
    Member member2 = new Member("member2", "회원2");
    member2.setTeam(team1);  // 연관관계 설정 member2 -> team2
    em.persist(member2);
}

JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 한다.

중요한 부분을 분석해보자.

member1.setTeam(team1);  // 회원 -> 팀 참조
em.persist(member1);   // 저장

회원 엔티티는 팀 엔티티를 참조하고 저장했다. JPA는 참조한 팀의 식별자(Team.id)를 외래 키로 사용해서 적절한 등록 쿼리를 생성한다. 이때 실행된 SQL은 다음과 같다. 이 SQL을 보면 회원 테이블의 외래 키 값으로 참조한 팀의 식별자값인 team1이 입력된 것을 확인할 수 있다.

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');

데이터가 잘 입력되었는지 다음 SQL로 데이터베이스에서 확인해보자.

SELECT M.MEMBER_ID, M.NAME, M.TEAM_ID, T.NAME AS TEAM_NAME
FROM MEMBER M
    JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID

결과는 다음과 같다.

MEMBER_ID NAME TEAM_ID TEAM_NAME
member1 회원1 team1 팀1
member2 회원2 team1 팀1

2. 조회

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

  • 객체 그래프 탐색(객체 연관관계를 사용한 조회)
  • 객체지향 쿼리 사용(JPQL)

방금 저장한 대로 회원1, 회원2가 팀1에 소속해 있다고 가정하자.

객체 그래프 탐색

member.getTeam()을 사용해서 member와 연관된 team 엔티티를 조회할 수 있다.

Member member = em.find(Member.class, "member1");
Team team = member.getTeam();  // 객체 그래프 탐색
System.out.println("팀 이름 = " + team.getName());

// 출력 결과 : 팀 이름 = 팀1

이처럼 객체를 통해 연관된 엔티티를 조회하는 것을 객체 그래프 탐색이라 한다.

객체지향 쿼리 사용

객체지향 쿼리인 JPQL에서 연관관계를 어떻게 사용하는지 알아보자.

예를 들어 회원을 대상으로 조회하는데 팀1에 소속된 회원만 조회하려면 회원과 연관된 팀 엔티티를 검색 조건으로 사용해야 한다. SQL은 연관된 테이블을 조인해서 검색조건을 사용하면 된다. JPQL도 조인을 지원한다(문법은 약간 다르다).

팀1에 소속된 모든 회원을 조회하는 아래 예제 JPQL을 보자.

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();
    
    for (Member member : resultList) {
        System.out.println("[query] member.username=" +
            member.getUsername());
    }
}
// 결과 : [query] member.username=회원1
// 결과 : [query] member.username=회원2

JPQL의 from Member m join m.team t 부분을 보면 회원이 팀과 관계를 가지고 있는 필드(m.team)를 통해서 Member와 Team을 조인했다. 그리고 where 절을 보면 조인한 t.name을 검색조건으로 사용해서 팀1에 속한 회원만 검색했다.

다음 실행한 JPQL을 보자. 참고로 :teamName과 같이 :로 시작하는 것은 파라미터를 바인딩받는 문법이다.

select m from Member m join m.team t
where t.name=:teamName

이때 실행되는 SQL은 다음과 같다.

SELECT M.* FROM MEMBER MEMBER
INNER JOIN
    TEAM TEAM ON MEMBER.TEAM_ID = TEAM1_.ID
WHERE
    TEAM1_.NAME='팀1'

실행된 SQL과 JPQL을 비교해보면 JPQL은 객체(엔티티)를 대상으로 하고 SQL보다 간결하다.

3. 수정

이번에는 연관관계를 어떻게 수정하는지 아래 예제를 통해 알아보자. 팀1 소속이면 회원을 새로운 팀2에 소속하도록 수정해보자.

private static void updateRelation(EntityManger em) {
    
    // 새로운 팀2
    Team team2 = new Team("team2", "팀2");
    em.persist(team2);
    
    // 회원1에 새로운 팀2 설정
    Member member = em.find(Member.class, "member1");
    member.setTeam(team2);
}

실행되는 수정 SQL은 다음과 같다.

UPDATE MEMBER
SET 
    TEAM_ID='team2', ...
WHERE
    ID='member1'

수정은 em.update() 같은 메소드가 없다. 단순히 불러온 엔티티의 값만 변경해두면 트랜잭션을 커밋할 때 플러시가 일어나면서 변경 감지 기능이 작동한다. 그리고 변경사항을 데이터베이스에 자동으로 반영한다. 이것은 연관관계를 수정할 때도 같은데, 참조하는 대상만 변경하면 나머지는 JPA가 자동으로 처리한다.

4. 연관관계 제거

이번에는 연관관계를 제거해보자. 아래 예제를 실행해서, 회원1을 팀에 소속하지 않도록 변경하자.

private static void deleteRelation(EntityManager em) {

    Member member1 = em.find(Member.class, "member1");
    member1.setTeam(null)l
}

위의 예제를 보면 연관관계를 null로 설정했다. 이때 실행되는 연관관계 제거 SQL은 다음과 같다.

UPDATE MEMBER
SET
    TEAM_ID=null, ...
WHERE
    ID='member1'

5. 연관된 엔티티 삭제

연관된 엔티티를 삭제하려면 기존에 있던 연관관계를 먼저 제거하고 삭제해야 한다. 그렇지 않으면 외래 키 제약조건으로 인해, 데이터베이스에서 오류가 발생한다. 팀1에는 회원1과 회원2가 소속되어 있다. 이때 팀1을 삭제하려면 연관관계를 먼저 끊어야 한다.

member1.setTeam(null);  // 회원1 연관관계 제거
member2.setTeam(null);  // 회원2 연관관계 제거
em.remove(team);        // 팀 삭제

참고

  • 자바 ORM 표준 JPA 프로그래밍

좋은 웹페이지 즐겨찾기