TIL

효준·2024년 11월 21일
0

11월 21일 목요일
AM 알고리즘 풀이, 과제 수행
PM 과제 수행

💡 Today Issue

Spring JPA 연관관계

🤔 나의 생각 + 배운 것

다양한 연관관계

  • 1:1 | @OneToOne
  • 1:N | @OneToMany
  • N:1 | @ManyToOne
  • N:M | @ManyToMany

N:M 연관관계는 RDM에서 일반적인 방법으로 표현할 수 없어서 중간테이블이 생기게 됩니다.

따로 중간 테이블을 만들어서 1:N, N:1 관계로 분해하지 않으면 관리가 힘들어지기 때문에 사용을 권장하지 않습니다.

1:1 연관관계도 사용 시 객체 지향적으로 개발할 수 있다는 점 등 장점도 있지만, 단점도 존재하기에 주의해서 사용해야 됩니다.

@One To Many,@Many To One 사용법

@Entity
@Getter @Setter
public class User {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany
    private List<Post> posts;

    @OneToMany
    private List<Comment> comments;
}

@Entity
@Getter @Setter
public class Post {
    @Id @GeneratedValue
    private Long id;

    private String title;

    @ManyToOne
    private User user;

    @OneToMany
    private List<Comment> comments;
}

@Entity
@Getter @Setter
public class Comment {
    @Id @GeneratedValue
    private Long id;

    private String text;

    @ManyToOne
    private Post post;

    @ManyToOne
    private User user;
}

양방향과 단방향 연관관계

@One To Many 기준

  • 단방향 : 상대 엔티티에 @ManyToOne이 없는 경우
  • 양방향 : 상대 엔티티에 @ManyToOne이 있는 경우

@Many To One 기준

  • 단방향 : 상대 엔티티에 @OneToMany가 없는 경우
  • 양방향 : 상대 엔티티에 @OneToMany가 있는 경우

서로 각 방향의 반대 상황이라고 생각하면 된다.

연관관계의 주인 : mappedBy

연관관계에는 주인이라는 개념이 있다.

주인은 연관관계의 관리 주체이며, 주인은 이 연관관계를 관리할 책임이 있다.

언뜻 생각하기에 부모 엔티티가 주인 엔티티가 아닌가 생각할 수 있지만 주인 엔티티와 부모 엔티티는 분명히 다르다.

@ManyToOne 단방향

가장 많이 쓰이는 연관관계입니다. 엔티티의 관계를 표현하고 FK 관리에 있어서 가장 자연스럽기 때문입니다.

@JoinColumn 어노테이션과 함께 쓰이며, 이때 @JoinColumn은 엔티티 테이블에 FK 칼럼을 정의해줍니다.

/* Post.java */
@ManyToOne
@JoinColumn
private User user

@OneToMany 단방향

상대 엔티티를 참조할 수 있는 매핑이 부모 엔티티 쪽에 존재하지만, FK는 자식 엔티티 테이블에 존재하는 연관관계입니다.

@JoinColumn없이 사용할 경우, Hibernate에서 자체적으로 중간 테이블(link table)을 생성해서 연관관계를 관리하게 됩니다.

create table "user" (
    id bigint generated by default as identity,
    name varchar(255),
    primary key (id)
)
create table "user_posts" (
    "user_id" bigint not null,
    posts_id bigint not null
)
create table post (
    id bigint generated by default as identity,
    title varchar(255),
    primary key (id)
)

post 테이블에 FK 칼럼이 없기 때문에 user와 post 테이블을 연결할 수 있도록 중간 테이블이 생성되었습니다.

이렇게 되면 FK칼럼을 만드는 것보다 비효율적이며, 무엇보다 자식 엔티티를 제거할 때 심각한 성능 문제로 이어질 수 있습니다. 밑에서 더 자세히 다루겠습니다.

따라서, 이를 방지하기 위해 @JoinColumn을 같이 사용할 수 있습니다.

/* User.java */
@OneToMany
@JoinColumn(name = "user_id")
private List<Post> posts;

@ManyToOne 양방향 (@OneToMany 양방향)

단방향 @ManyToOne과 더불어 가장 많이 쓰이는 연관관계입니다.

DB 관점에서는 단방향 @ManyToOne과 차이점이 없으며, 어플리케이션에서 상대 엔티티쪽에서 참조할 수 있는 변수가 생기는 장점이 있습니다.

/* User.java */
@OneToMany(mappedBy = "user")
private List<Post> posts;

/* Post.java */
@ManyToOne
@JoinColumn
private User user

@OneToMany쪽에 mappedBy를 설정해서 상대 엔티티에서 어떻게 매핑이 되어 있는 지를 설명하고 @ManyToOne쪽에서 @JoinColumn을 통해 같은 테이블 내에서 FK 칼럼을 정의합니다.

여기서 @OneToMany에 mappedBy를 설정하지 않으면 @OneToMany가 단방향처럼 취급되어 중간 테이블이 생성되기 때문에 주의가 필요합니다.

@OneToMany, @ManyToOne 편의 옵션

프록시 옵션: fetch

해당 객체를 DB에서 조회할 때, 연관관계에 있는 엔티티의 정보를 언제 같이 끌어올 지를 결정한다.

  • Lazy Fetch

연관관계에 있는 엔티티에 접근할 때, DB에 쿼리를 날려 엔티티를 조회하게 됩니다.

접근하지 않는 경우, 쿼리가 발생하지 않습니다.

  • Eager Fetch

상대 엔티티의 조회 여부와 상관없이, 쿼리가 발생하게 됩니다.

@OneToMany의 기본값은 Lazy Fetch이며, @ManyToOne의 기본값은 Eager Fetch입니다.

Eager Fetch, Lazy Fetch 상관 없이 단건 조회가 아닌 컬렉션 조회에서 N+1 문제가 발생할 수 있습니다.

Eager Fetch는 조회 여부와 상관없이 쿼리가 발생하기 때문에, 더 잘 보이는 차이가 있을 뿐입니다.

영속성 전파: cascade

CascadeType으로 6가지를 줄 수 있습니다.

PERSIST, MERGE, REMOVE, REFRESH, DETACH와 모든 옵션을 줄 수 있는 ALL입니다.

영속성 전파를 설정하게 되면, 객체에 해당 작업이 이루어질 때, 자식엔티티에도 작업이 전파됩니다.

예를 들어, 유저의 posts에 cascadeType으로 PERSIST가 걸려있으면, 유저 객체만 저장해도 글 객체도 저장됩니다.

Null 관리: optional

optional 옵션은 @ManyToOne에만 존재하는 옵션입니다.

해당 옵션은 FK 칼럼에 Null 여부를 설정합니다.

기본값은 true이며, false인 경우, FK에 Null을 허용하지 않습니다.

https://velog.io/@goniieee/JPA-OneToMany-ManyToOne%EC%9C%BC%EB%A1%9C-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0

🕐회고

여전히 배울게 많다고 느낀다

profile
사진은 캣타워가 생겨 포효하는 고양이입니다.

0개의 댓글

관련 채용 정보