연관 관계 매핑 종류
-
일대일(1:1) : @OneToOne
-
일대다(1:N) : @OneToMany
-
다대일(N:1) : @ManyToOne
-
다대다(N:N) : @ManyToMany
-
단방향과 양방향
- 데이터베이스 테이블은 외래 키 하나로 양 쪽 테이블 조인이 가능하기 때문에 단방향, 양방향을 나눌 필요가 없다.
그러나 객체는 참조용 필드가 있는 객체만 다른 객체를 참조하는 것이 가능하다. 그렇기 때문에 두 객체 사이에 하나의 객체만 참조용 필드를 갖고 참조하면 단방향 관계, 두 객체 모두가 각각 참조용 필드를 갖고 참조하면 양방향 관계라고 한다. (엄밀하게는 양방향 관계↔️는 없고 두 객체가 단방향 참조를 각각 가져서 양방향 관계라고 칭한다.)
- 책에서의 코드를 보면 장바구니(Cart) 엔티티가 일방적으로 회원(Member) 엔티티를 참조하고 있다. 즉 장바구니와 회원은 일대일로 매핑돼 있으며, 장바구니 엔티티가 회원 엔티티를 참조하는 일대일 단방향 매핑이다.
즉시 로딩
- 엔티티를 조회할 때 해당 엔티티와 매핑된 엔티티도 한 번에 조회하는 것을 '즉시 로딩'이라고 한다. 일대일, 다대일로 매핑할 경우 즉시 로딩을 기본 Fetch 전략으로 설정한다. Cart.java 클래스에서 member 엔티티와 일대일 매핑 관계를 맺어줄 때 따로 옵션을 주지 않으면 아래 코드와 같이 FetchType.EAGER(즉시 로딩)로 설정하는 것과 동일하다.
@OneToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "member_id")
private Member member;
연관관계주인
- 양방향 매핑에서는 '연관 관계 주인'을 잘 설정해야한다.
- 엔티티는 테이블과 다르기 때문에 엔티티를 양방향 연관 관계로 설정하면 객체의 참조는 둘인데 외래키는 하나이므로 둘 중 누가 외래키를 관리할지를 정해야한다.
- 연관 관계의 주인은 외래키가 있는 곳으로 설정
- 연관 관계의 주인이 외래키를 관리 (등록, 수정, 삭제)
- 주인이 아닌 쪽은 연관 관계 매핑 시 mappedBy 속성의 값으로 연관 관계의 주인을 설정
- 주인이 아닌 쪽은 읽기만 가능
- Order.java
Order 엔티티는 OrderItem 엔티티와 일대다 매핑을 한다. 외래키가 Order_item테이블에 있으므로 연관관계의 주인은 OrderItem 엔티티이다. mappedBy의 속성으로 "order"를 적어준 이유는 OrderItem에 있는 Order에 의해 관리된다는 의미로 해석하면 된다.
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems = new ArrayList<>();
다대다 매핑
- 다대다 매핑은 실무에서 사용하지 않는 매핑관계이다.
- 관계형 데이터베이스는 정규화된 테이블 2개로 다대다를 표현할 수 없다. 따라서 연결 테이블을 생성해서 다대다관계를 일대다, 다대일 관계로 풀어낸다.
영속성 전이
- 영속성 전이란 엔티티의 상태를 변경할 때 해당 엔티티와 연관된 엔티티의 상태 변화를 전파시키는 옵션이다.
- 이때 부모는 One에 해당하고 자식은 Many에 해당한다. 예를 들어 Order 엔티티가 삭제되었을 때 해당 엔티티와 연관되어 있는 OrderItem 엔티티가 함께 삭제 되거나, Order 엔티티를 저장할 때 Order 엔티티에 담겨있던 OrderItem 엔티티를 한꺼번에 저장할 수 있다.
CASCADE 종류 | 설명 |
---|
PERSIST | 부모 엔티티가 영속화될 때 자식 엔티티도 영속화 |
MERGE | 부모 엔티티가 병합될 때 자식 엔티티도 병합 |
REMOVE | 부모 엔티티가 삭제될 때 연관된 자식 엔티티도 삭제 |
REFRESH | 부모 엔티티가 refresh되면 연관된 자식 엔티티도 refresh |
DETACH | 부모 엔티티가 detach되면 연관된 자식 엔티티도 detach 상태로 변경 |
ALL | 부모 엔티티의 영속성 상태 변화를 자식 엔티티에 모두 전이 |
지연 로딩
-
일대일, 다대일로 매핑할 경우 기본 전략인 즉시 로딩을 통해 엔티티를 함께 가지고 온다. 따라서 예를 들어 Order 엔티티를 조회할 때 자신과 다대일로 매핑된 Member 엔티티도 가지고 온다. 작성하고 있는 비즈니스 로직에서 사용하지 않을 데이터도 한꺼번에 들고 오는 것이다. -> 사용하지 않는 데이터도 한꺼번에 조회하기 때문에 성능문제가 생기고 실무에서 사용하지 않는다.
-
FetchType.LAZY 방식으로 설정할 수 있고 이처럼 지연 로딩으로 설정하면 해당 클라스를 조회했을 때 실제 엔티티 대신에 프록시 객체를 넣어둔다. 프록시 객체는 실제로 사용되기 전까지 데이터 로딩을 하지 않고, 실제 사용 시점에 조회 쿼리문이 실행된다.
Auditing
- 실제 서비스를 운영할 때 보통 등록시간과 수정시간, 등록자, 수정자를 테이블에 넣어놓고 활용을 한다. Spring Data Jpa에서는 Auditing 기능을 제공하여 엔티티가 저장 또는 수정될 때 자동으로 등록일, 수정일, 등록자, 수정자를 입력해준다.