티스토리 뷰

Spring

[JPA] 엔티티 설계 시 주의점

roopreDev 2023. 12. 17. 18:40

엔티티 설계 시 주의점

엔티티에는 가급적 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. 대문자 -> 소문자

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
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
글 보관함