[JPA] 다양한 연관관계 매핑 - 다대일, 일대다

Hocaron·2022년 3월 8일
1

Spring

목록 보기
18/47

다중성

JPA는 객체가 기준이지만, 다중성데이터베이스가 기준이다.
연관 관계는 대칭성을 갖는다.

다대일(N : 1)

게시판(Board)과 게시글(Post)이 있다.

요구사항

  • 하나의 게시판에는 여러 게시글을 작성할 수 있다.
  • 하나의 게시글은 하나의 게시판에만 작성할 수 있다.
  • 게시글과 게시판은 다대일 관계를 갖는다.
    게시글N : 게시판1, 즉, 외래 키를 게시글(N)이 관리하는 일반적인 형태이다.

다대일(N:1) 단방향

@Entity 
public class Post { 
	@Id @GeneratedValue 
    @Column(name = "POST_ID") 
    private Long id; 		
    
    @Column(name = "TITLE") 
    private String title; 
    
    @ManyToOne 
    @JoinColumn(name = "BOARD_ID") 
    private Board board; 
    //... getter, setter 
 } 
    
@Entity 
public class Board { 
	@Id @GeneratedValue 
    private Long id; 
    private String title; 
    //... getter, setter 
}

다대일 단방향에서는 다 쪽인 Post에서 @ManyToOne 만 추가해줬다.

다대일(N:1) 양방향

@Entity 
public class Post { 
	@Id @GeneratedValue 
    @Column(name = "POST_ID") 
    private Long id; 
    
    @Column(name = "TITLE") 
    private String title; 
    
    @ManyToOne 
    @JoinColumn(name = "BOARD_ID") 
    private Board board; 
    //... getter, setter 
} 

@Entity 
public class Board { 
	@Id @GeneratedValue 
    private Long id; 
    
    private String title; 
    
    @OneToMany(mappedBy = "board") 
    List<Post> posts = new ArrayList<>(); 
    //... getter, setter 
}
  • 다대일 관계에서 단방향 매핑을 진행하고, 양방향 매핑을 진행할 때
  • 반대쪽에서 일대다 단방향 매핑을 해주면 된다.(객체에서 컬렉션 추가해주면 된다.)
  • 여기서 중요한건, 반대에서 단방향 매핑을 한다고 해서 DB 테이블에 영향을 전혀 주지 않는다.
  • 다대일관계의 다 쪽에서 이미 연관관계의 주인이 되어서 외래키를 관리하고 있다.

다대일 양방향으로 만드려면 일(1) 쪽에 @OneToMany 를 추가하고 양방향 매핑을 사용했으니 연관관계의 주인이 아니고, 어디에 매핑 됐는지에 관한 정보 mappedBy를 꼭 넣어줘야 한다.
mappedBy로 지정할 때 값은 대상이 되는 변수명을 따라 지정하면 된다.

일대다(1:N)

데이터베이스 입장에서는 무조건 다(N)쪽에서 외래키를 관리한다.
하지만 일대다는 연관관계의 주인을 일(1)쪽에 둔것이다. 즉, 일(1)쪽 객체에서 다(N) 쪽 객체를 조작(생성,수정,삭제)하는 방법이다.

@Entity 
public class Post { 
	@Id @GeneratedValue 
    @Column(name = "POST_ID") 
    private Long id; 
    
    @Column(name = "TITLE") 
    private String title; 
    //... getter, setter 
} 

@Entity 
public class Board { 
	@Id @GeneratedValue 
    private Long id; 
    
    private String title; 
    
    @OneToMany 
    @JoinColumn(name = "POST_ID") //일대다 단방향을 @JoinColumn필수 
    List<Post> posts = new ArrayList<>(); 
    //... getter, setter 
}

일대다 단방향 매핑의 단점

//... 
Post post = new Post(); 
post.setTitle("가입인사"); 

entityManager.persist(post); // post 저장 

Board board = new Board(); 
board.setTitle("자유게시판"); 
board.getPosts().add(post); 
entityManager.persist(board); // board 저장 
//...

위와 같은 시나리오로 동작을 살펴보면, post를 저장할 때는 멀쩡하게 insert 쿼리가 나간다.
여기서 문제! board를 저장할 때는 Board를 insert하는 쿼리가 나간 후에 post를 update하는 쿼리가 나간다. board.getPosts().add(post); 부분 때문이다.

Board 엔티티는 Board 테이블에 매핑되기 때문에 Board 테이블에 직접 지정할 수 있으나, Post 테이블의 FK(BOARD_ID)를 저장할 방법이 없기 때문에 조인 및 업데이트 쿼리를 날려야 하는 문제가 있다.

🚨 치명적인 단점

  • 일만 수정한 것 같은데 다른 수정이 생겨 쿼리가 발생하는 것.
    • 업데이트 쿼리 때문에 성능상 이슈는 그렇게 크지는 않다.
      그렇기 때문에 TIP으로 일대다(1:N) 단방향 연관 관계 매핑이 필요한 경우는 그냥 다대일(N:1) 양방향 연관 관계를 매핑해버리는게 추후에 유지보수에 훨씬 수월하기 때문에 이 방식을 채택하는 것을 추천한다.

그런데 실무에서 사용을 금지하지 않는 이유는 되도록 피하는 게 좋지만, JPA 값 타입을 사용하는 것을 대신하여 사용할 때는 또 유용하다.
→ 일대다(1:N) 양방향 (실무 사용 금지 ❌)
@JoinColumn(updatable = false, insertable = false)로 읽기 전용으로 추가할 수 있지만...

결과적으로 일대다(1:N) 단방향, 양방향은 쓰지 말고 차라리 다대일(N:1) 양방향으로 쓰는 것이 맞다.

References

profile
기록을 통한 성장을

1개의 댓글

comment-user-thumbnail
2025년 6월 30일

Whether it’s for business or pleasure, Escorts Service in Janakpuri are your perfect companions. Enjoy dinner dates, private parties, or relaxing evenings with these elegant beauties. Choose a reputed Janakpuri Escorts Agency for safe, satisfying, and unforgettable experiences every time.

답글 달기