티스토리 뷰
엔티티 설계 시 주의점
엔티티에는 가급적 Setter를 사용하지 말자
Setter가 모두 열려있는 경우, 변경 포인트가 너무 많아서 유지보수가 어렵다.
모든 연관관계는 지연로딩으로 설정하자
- 즉시로딩(EAGER)은 예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어렵다. 특히 JPQL을 실행할 때 N+1 문제가 자주 발생한다.
- 실무에서 모든 연관관계는 지연로딩(LAZY)으로 설정해야 한다.
- 연관된 엔티티를 함께 DB에서 조회해야 하면, fetch join 또는 엔티티 그래프 기능을 사용한다.
- @XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩이므로 직접 지연로딩으로 설정해야한다. (@XToMany의 경우는 기본이 지연로딩이다.)
JPQL N+1 문제란?
JPQL로 select o from order o; 라는 쿼리를 실행시켰을 때 select * from order라는 쿼리가 실행되게 되고 JPA에서 각 Order의 비어있는 member를 가져오기 위해서 각 order마다 select * from member where member_id = 'member_id'; 라는 쿼리가 실행되게 된다. 즉 select해온 Order가 100개라면 select member 쿼리가 100개가 실행된다. 따라서 이러한 문제를 N+1 (첫번째 쿼리로 가져온 결과 수 + 첫번째 쿼리) 이라고 하고 해결하기 위해서 필요한 경우에만 select해오도록 지연로딩으로 설정한다.
컬렉션은 필드에서 초기화 하자.
- 컬렉션은 필드에서 바로 초기화 하는 것이 안전하다.
- null 문제에서 안전하다.
- Hibernate는 엔티티를 영속화 할 때, 컬렉션을 감싸서 Hibernate가 제공하는 내장 컬렉션으로 변경한다. 만약 임의의 메서드에서 컬렉션을 잘못 생성하면 Hibernate 내부 메커니즘에 문제가 발생할 수 있다. 따라서 필드 레벨에서 생성하는 것이 가장 안전하고 코드도 간결하다.
class Member {
. . .
@OneToMany(mappedBy="member")
public List<Order> orders = new ArrayList<>(); // 필드 레벨에서 초기화 해야함!
}
Member member = new Member();
System.out.println(member.getOrders().getClass());
em.persist(team);
System.out.println(member.getOrders().getClass());
// 출력 결과
// class java.util.ArrayList
// class org.hibernate.collection.internate.PersistentBag
테이블, 컬럼명 생성 전략
Spring Boot에서 Hibernate 기본 매핑 전략을 변경해서 실제 테이블 필드명은 다름
Hibernate 기존 구현 : 엔티티의 필드명을 그대로 테이블 명으로 사용
(SpringPhysicalNamingStrategy)
Spring Boot 신규 설정 (엔티티(필드) -> 테이블(컬럼))
1. Camel Case -> UnderScore (memberPoint -> member_point)
2. .(점) -> _(UnderScore)
3. 대문자 -> 소문자
'Spring' 카테고리의 다른 글
[Spring] Lombok 사용시 주의사항 (0) | 2023.04.20 |
---|---|
[Spring] ShedLock을 활용하여 스케줄러 동기화하기 (0) | 2022.12.20 |