티스토리 뷰

일대다(1:N) 연관관계란?

 일대다(1:N) 연관관계는 하나의 엔티티가 여러 개의 엔티티와 관계를 맺는 구조를 의미한다. 예를 들어 객체 구조에서 Team과 Member가 있을 때, 하나의 Team에는 여러 명의 Member가 속할 수 있고 각 Member는 하나의 Team에만 속하게 된다. 이러한 관계를 데이터베이스 테이블로 설계할 경우, 외래키는 항상 ‘다(N)’에 해당하는 쪽에 위치하게 되므로 Member 테이블에 Team의 기본키를 참조하는 외래키가 포함된다. 이때 일대다 연관관계에서 일 쪽에 외래키를 관리하며 연관관계의 주인이 된다.

 

예제

 아래의 코드는 일대다 관계에서 일 쪽에 단방향 연관관계의 주인이 될 때 주의할 점이다.

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;
    
    private String name;
    
    // getter, setter 생략
}
@Entity
public class Team {

    @Id
    @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    
    private String name;
    
    @OneToMany
    @JoinColumn(name = "TEAM_ID")
    private List<Member> members = new ArrayList<>();
    
    // getter, setter 생략
}

 

public class JpaMain {

    public static void main(String[] args) {

        // 엔티티 매니저 생성 및 트랜잭션 생략

        Member member1 = new Member();
        member1.setName("member1");
        em.persist(member1);

        Team team1 = new Team();
        team1.setName("Team1");
        team1.getMembers().add(member1);
        em.persist(team1);

        // 엔티티 매니저 종료 및 트랜잭션 생략
    }
}

 

실행결과

Hibernate: 
    /* insert for
        hellojpa.Member */insert 
    into
        Member (name, MEMBER_ID) 
    values
        (?, ?)
Hibernate: 
    /* insert for
        hellojpa.Team */insert 
    into
        Team (name, TEAM_ID) 
    values
        (?, ?)
Hibernate: 
    update
        Member 
    set
        TEAM_ID=? 
    where
        MEMBER_ID=?

 위의 코드를 실행하니 쿼리가 3개가 나왔다. 분명 영속한 객체(insert 하는)는 2개인데 insert 2개랑 update 1개 발생하였다.

 

update가 발생한 이유?

 지금 Team이 연관관계 주인이며, Member를 컬렉션으로 가지고 있는 단방향 관계이다. 즉, 외래키는 Member 테이블에 존재하지만, 이를 설정하는 주체는 Team이다. 코드를 보면 먼저 Member를 생성하고 persist를 호출하여 insert가 실행된다. 이 시점에는 Member가 어떤 Team에도 속해 있지 않기 때문에, 외래키 값(Team의 FK)은 null인 상태로 저장된다. 이후 Team을 생성하고 member1을 Team의 members 컬렉션에 추가한 뒤 persist를 호출하면, JPA는 이 시점에서 연관관계가 설정되었다고 인식한다. 하지만 이미 Member는 insert 된 상태이므로, 새로 insert 할 수는 없고 기존 데이터의 외래키 값을 수정해야 한다. 따라서 JPA는 Member 테이블의 외래키를 업데이트하기 위해 추가로 update 쿼리를 실행하게 된다.

 정리하면, Member를 먼저 저장할 때는 연관관계 정보가 없어서 FK가 null로 insert되고, 이후 Team에 Member를 추가하면서 FK 값을 반영하기 위해 update가 발생하는 것이다.

 

구조를 지양하는 이유?

 이 구조(일대다 단방향 + Team이 연관관계 주인)를 실무에서 잘 사용하지 않는 이유는 성능과 설계 측면에서 비효율적이기 때문이며, 가장 큰 문제는 불필요한 update 쿼리 발생이다. 앞서 본 것처럼 insert 한 번으로 끝낼 수 있는 작업이 insert + update로 늘어나 성능 손해가 발생한다. 또한 이 방식은 데이터 흐름이 직관적이지 않는다. 실제 데이터베이스에서는 외래키가 Member 테이블에 존재하기 때문에, Member가 Team을 참조하는 구조가 자연스럽다. 그런데 객체에서는 Team이 Member를 관리하게 되므로, 객체 구조와 DB 구조가 어긋나는 문제가 생긴다. 이로 인해 유지보수 시 혼란이 발생할 수 있다.

 

정리

 일대다 단방향 연관관계에서 ‘일(1)’ 쪽을 연관관계의 주인으로 설정하면, 실제 외래키는 ‘다(N)’ 쪽 테이블에 존재함에도 불구하고 이를 ‘일’ 쪽에서 관리하게 되어 구조가 비직관적이 된다. 이로 인해 엔티티를 저장할 때 외래키 값이 즉시 반영되지 못하고, insert 이후 추가적인 update 쿼리가 발생하는 비효율이 생긴다. 또한 객체 구조와 데이터베이스 구조가 어긋나 유지보수와 성능 측면에서 불리하다. 따라서 실무에서는 일대다 단방향 대신, 외래키를 가진 ‘다(N)’ 쪽을 연관관계의 주인으로 하는 다대일 중심의 설계를 사용하는 것이 바람직하다.

 


본 포스팅은 “자바 ORM 표준 JPA 프로그래밍 - 기본편/인프런”를 학습한 내용을 정리한 것

댓글
최근에 올라온 글
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함
Total
Today
Yesterday