[스프링 부트 핵심가이드] JPA 연관관계 매핑✨

FeelingXD·2023년 4월 9일
0

북스터디

목록 보기
6/13
post-thumbnail

연관관계란?

연관관계는 객체 간의 관계를 말합니다. 객체지향 프로그래밍에서는 객체들 간의 관계를 매우 중요하게 다룹니다. 이러한 객체 간의 관계를 데이터베이스에 저장하기 위해서는 연관관계를 매핑해주어야 합니다.

연관관계 매핑 종류와 방향

연관관계 매핑에는 크게 다음과 같은 종류와 방향이 있습니다.

종류

  • 다대일: 다 쪽에 외래키가 있음 @ManytoOne
  • 일대다: 일 쪽에 외래키가 있음 @OnetoMany
  • 일대일: 주 테이블에 외래키가 있음 @OnetoOne
  • 다대다: 연결 테이블을 추가하여 일대다, 다대일 관계로 풀어냄 @ManytoMany (사용시 관계의 분리가 필요함)

방향

  • 단방향: 한 쪽에서만 참조가 가능한 방향
  • 양방향: 양쪽에서 서로 참조가 가능한 방향

JPA에서는 각 연관관계에 따라 어떤 매핑을 사용해야 하는지에 대한 규칙이 있으므로, 이를 잘 이해하고 사용해야 합니다.

영속성 전이 와 RDB의 종속성

영속성전이는 jpa객체에서 RDB의 종속성관계를 표현하는것의 연장선이라고 생각하면좋다.
sql의 cascade 옵션처럼 jpa에서도 어노테이션을 통해 어떤관계이며 어떤정책으로 엔티티를 다룰지 정할수 있다.

jpa에서 영속성 타입

  • ALL : 모든 영속 상태 변경에 대해 영속성 전이를 적용 (모두 포함됨)
  • PERSIST : 엔티티가 영속화할 때 연관된 엔티티도 함께 영속화
  • MERGE : 영속성 컨텍스트에 병합할 때 연관된 엔티티도 병합
  • REMOVE : 제거할 때 연관된 엔티티도 제거
  • REFRESH : 새로고침할 때 연관된 엔티티도 새로고침
  • DETACH : 영속성 컨텍스트에서 제외하면 연관된 엔티티도 제외

jpa 에서의 고아객체

jpa에서 고아객체란 해당엔티티의 부모의 엔티티와 연관관계가 변경되면서 끊어진 객체를 고아객체라고 표현한다. jpa에서는 기본적으로 고아객체에대해서 테이블의 데이터간 일관성을 해치기에 고아객체가되면 자동으로 제거하는경우가 생긴다.
이런경우 만약 고아객체가된 엔티티에서 부모 엔티티를 제외한 다른 엔티티와 연관관계인경우 문제가 생기므로 어노테이션 설정을통해 추가적으로 관리해야한다.

Jpa 연관관계와 RDB에서의 차이

Jpa 를 통한 데이터베이스 사용은 java entity 객체와 RDB 사이의 칼럼을 매칭한다. 하지만

자바 엔티티객체의 필드로 객체 관계를 매핑하여 표현하는 방법은 RDB와 조금 다릅니다.

위와같이 키오스크를 가지고있는 상점에대한 RDB 테이블로 나타내었을때 각각 자바엔티티로 나타낸다면

public class Kiosk { //키오스크
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @ManyToOne
    Shop shop;
}
public class Shop { //상점

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;


    @OneToMany(mappedBy = "shop" , fetch =FetchType.LAZY)
    private List<Kiosk> kiosk = new ArrayList<>();


    private String name;

    private String phone;
    private String location;

}

처럼 객체관계를 표현할수있을것이다.

Java의 객체관점에서 보았을때는 상점이라는 클래스가 kiosk로 이루어진 리스트를 포함하고있으며 각각의 키오스크는 id를 가지고있다 라고표현할수있다.

sql 에서는 shop -> kiosk ,kiosk ->shop을 찾는데 제약사항이 추가적으로 발생하지않지만 .

Java 의관점에서는 Shop->kiosk 은 될수있으도 shop에 포함되는 kiosk가 자신의 상위객체인 shop을 바라볼수없다. ( @OneToMany(mappedBy = "shop" , fetch =FetchType.LAZY), @ManyToOne 어노테이션으로 표현하지않는다면)

그러기에 jpa에서는 '관계의 주인' 형태로 누가 외부키를 관리할지 mappedBy 속성으로 지정한다.

또한 kiosk에서 자신의 상위객체를 바라볼수있도록 kiosk 영속성에서 추가해주어야한다. 처음 jpa를 sql처럼 생각했을때 문제가 되었던 부분이다.


Shop s= new Shop();

Kiosk k = new Kiosk();
	

s.kiosk.add(k) //=> ❌ 이렇게 사용한다면 shop -> kiosk는 바라볼수 있어도 kiosk가 shop을 바라볼수없음

k.setShop(s) //=> ✔️ kiosk에 상점관계를 표시함으로써 kiosk.getShop()으로  포함되어있는 상점에 접근할수있음

@OneToMany, @ManyToOne 등
관계의 주인은 항상 Many 쪽으로 선언하며 One이 되는 entity에 mappedby 속성으로 관계의 주인이 다른 entity임을 명시해주어야한다. 그래야 One->Many , Many->One 서로를 바라보는 양방향 관계가 정립된다.
profile
tistory로 이사갑니다. :) https://feelingxd.tistory.com/

0개의 댓글