[ JPA ] 엔티티 클래스 개발
[ 엔티티 설계시 주의점 ]
엔티티에는 Setter를 사용하지 말자!
setter가 모두 열려있다면, 변경포인트가 너무많아서 이후에 유지보수시에 어려워진다.
모든 연관관계는 지연로딩으로 설정!
즉시로딩( EAGER )은 예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어렵다.
특히 JPQL을 실행할 때 N+1 문제 가 자주 발생한다.
실무에서 모든 연관관계는 지연로딩( LAZY )으로 설정해야 한다.
연관된 엔티티를 함께 DB에서 조회해야 하면, fetch join 또는 엔티티 그래프 기능을 사용한다.
@OneToMany(mappedBy = "order" ,cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name="delivery_id")
private Delivery delivery;
@XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩(EAGER) 이므로 직접 지연로딩(LAZY)으로 설정해야 한다.
컬렉션은 필드에서 초기화 하자
컬렉션을 필드에서 초기화하는것이 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
테이블, 컬럼명 생성 전략
스프링 부트에서 하이버네이트 기본 매핑 전략을 변경해서 실제 테이블 필드명은 다르다.
> 하이버네이트 기존 구현 : 엔티티의 필드명을 그대로 테이블의 컬럼명으로 사용
>> 스프링 부트 신규 설정 (엔티티(필드) -> 테이블(컬럼))
① 카멜 케이스 -> 언더스코어 (orderDate -> order_date)
② .(점) -> _(언더스코어)
③ 대문자 -> 소문자