티스토리 뷰

1)실무에서는 `@ManyToMany` 를 사용하지 말자

`@ManyToMany` 는 편리한 것 같지만, 중간 테이블( `CATEGORY_ITEM` )에 컬럼을 추가할 수 없고, 세밀하게 쿼리

를 실행하기 어렵기 때문에 실무에서 사용하기에는 한계가 있다. 중간 엔티티( `CategoryItem` 를 만들고 `@ManyToOne` , `@OneToMany` 로 매핑해서 사용하자. 정리하면 다대다 매핑을 일대다, 다대일 매핑으로 풀어내

서 사용하자.

package jpabook2.jpashop2.domain;

import jakarta.persistence.Embeddable;
import lombok.Getter;

@Embeddable //jpa 내장타입
@Getter
public class Address {

    private String city;
    private String street;
    private String zipcode;

    protected Address() { // 엔티티나 임베디드 타입은 jpa 스팩상에 기본생성자가 꼭 필요하다.
    }

    public Address(String city, String street, String zipcode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }
}

2) 값 타입은 변경 불가능하게 설계해야 한다.
`@Setter` 를 제거하고, 생성자에서 값을 모두 초기화해서 변경 불가능한 클래스를 만들자. JPA 스펙상 엔티티나

임베디드 타입( `@Embeddable` )은 자바 기본 생성자(default constructor)`public` 또는 `protected` 로 설정해야 한다. `public` 으로 두는 것 보다는 `protected` 로 설정하는 것이 그나마 더 안전하다.
JPA
가 이런 제약을 두는 이유는 JPA 구현 라이브러리가 객체를 생성할 때 리플랙션 같은 기술을 사용할 수 있도 록 지원해야 하기 때문이다.

 

3)엔티티에는 가급적 Setter를 사용하지 말자

Setter가 모두 열려있다. 변경 포인트가 너무 많아서, 유지보수가 어렵다. 나중에 리펙토링으로 Setter 제거

 

4)모든 연관관계는 지연로딩으로 설정!

즉시로딩( `EAGER` )은 예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어렵다. 특히 JPQL을 실행할 때 N+1 문제

가 자주 발생한다.
실무에서 모든 연관관계는 지연로딩( `LAZY` )으로 설정해야 한다.
연관된 엔티티를 함께 DB에서 조회해야 하면, fetch join 또는 엔티티 그래프 기능을 사용한다. @XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩이므로 직접 지연로딩으로 설정해야 한다.

@ManyToOne, @OneToOne 기본이 EAGER이고 @OneToMany는 LAZT이다. 

(인텔리제이 기준 shift + command + f 를 누르고 @ManyToOne을 검색해서 

@ManyToOne(fetch = FetchType.LAZY)

로 바꿔준다.

 

 

    @OneToMany(mappedBy = "member") //하나의 member에서 여러개의 order이다. mappedBy를 연관관계의 주인을 지정한다. 주인인 order 클래스 쪽은 그대로 두고 아래의 무엇으로 지정이 되는지 필드명을 적어준다. 이곳의 값을 변경한다고 해서 fk값이 변경되지 않는다.
    private List<Order> orders;

    public Member(Long id) {
        this.orders= new ArrayList<>();
    }

이렇게 사용하지 말고

    @OneToMany(mappedBy = "member") //하나의 member에서 여러개의 order이다. mappedBy를 연관관계의 주인을 지정한다. 주인인 order 클래스 쪽은 그대로 두고 아래의 무엇으로 지정이 되는지 필드명을 적어준다. 이곳의 값을 변경한다고 해서 fk값이 변경되지 않는다.
    private List<Order> orders = new ArrayList<>();

 

이렇게 사용하라

5)컬렉션은 필드에서 초기화 하자.

컬렉션은 필드에서 바로 초기화 하는 것이 안전하다.

`null` 문제에서 안전하다.
하이버네이트는 엔티티를 영속화 할 때, 컬랙션을 감싸서 하이버네이트가 제공하는 내장 컬렉션으로 변경한다. 만 약 `getOrders()` 처럼 임의의 메서드에서 컬력션을 잘못 생성하면 하이버네이트 내부 메커니즘에 문제가 발생 할 수 있다. 따라서 필드레벨에서 생성하는 것이 가장 안전하고, 코드도 간결하다.

 

Member member = new Member();
 System.out.println(member.getOrders().getClass());
 em.persist(member);
 System.out.println(member.getOrders().getClass());
//출력 결과
 class java.util.ArrayList
 class org.hibernate.collection.internal.PersistentBag

 

위의 코드처럼 한번 persist를 날리고 나면 값이 변경된다. 이건 하이버네이트에서 추적을 위해 변경하게 된다. 그러므로 가급적 set하지 말고 그대로 사용해야 한다고 한다.

 

 

'dev_공부일지 > spring JPA 활용 웹만들기' 카테고리의 다른 글

jpa 강점  (1) 2024.01.08
jpa 실무 시에 주의점(2)  (1) 2024.01.03
jpa 와 db 연동하기  (0) 2024.01.02
view 환경 설정  (0) 2023.12.30
라이브러리 셋팅  (0) 2023.12.30
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
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
글 보관함