티스토리 뷰
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
- 리터럴
- 백엔드 개발자 역량
- exception
- 컨트
- 항해플러스
- 로그인
- jpa api
- react실행
- hypertexttransferprotocol
- 인터셉터
- HTTP
- 향해플러스
- 백엔드 개발자 공부
- 향해플러스백엔드
- 스프링공부
- 향해99
- thymleaf
- reject
- 항해99
- filter
- 스프링부트
- Java
- 예외처리
- ArgumentResolver
- BindingResult
- SpringBoot
- JPA
- Intercepter
- React
- rejectValue
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |