엔티티 설계시 주의점

  1. 엔티티에는 가급적 Setter 사용❌ Setter가 모두 열려있으면 변경 포인트가 너무 많아서 유지보수 어렵다! =>리팩토링 시에 Setter 모두 제거! Setter를 둔다고 해도 의미있는 이름의 메서드로 만들어서 명시적으로 알아보기 쉽게 만든다!

  2. @XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩(EAGER)이므로 직접 지연로딩(LAZY)으로 설정해야 한 다.⭐️⭐️⭐️⭐️⭐️(OneToMany : LAZY)

    그렇지 않으면 Order 하나랑 이와 연관된 Member 하나 조회하려고 해도 100개가 조회된다. (N+1(order)) 데이터 하나를 가져오려고 하지만 연관된 데이터들 다 가져오는 문제. 이는 곧 JPA 성능 저하로 이어지기 때문에 실무에서는 EAGER 절대 쓰면 안 된다! 그런데 LAZY를 못 쓰는 상황이라면? LAZY 로딩는 트랜잭션 밖에서 로딩이 안 되는 이슈가 있다. 이러한 LAZY 로딩 Exception경우에도 EAGER 가 아니라 트랜잭션을 좀 빨리 가져온다거나 상황에 따라서는 open session xxx 같은 다른 대안들이 있다. 궁극적인 해결책은 fetch join으로 해결이 된다고 한다.

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

  4. 테이블, 컬럼명 생성 전략 : 스프링 부트에서 하이버네이트 기본 매핑 전략을 변경해서 실제 테이블 필드명은 다름 스프링 부트 신규 설정 (엔티티(필드) => 테이블(컬럼)) 1. 카멜 케이스 언더스코어(memberPoint memberpoint) 2. .(점) (언더스코어) 3. 대문자 소문자

  5. 적용 2단계 ① 논리 이름 : 명시적으로 컬럼, 테이블명을 직접 적지 않으면 ImplicitNamingStrategy 사용 테이블이나, 컬럼명을 명시하지 않을 때 논리명 적용 spring.jpa.hibernate.naming.implicit-strategy

    ② 물리 이름 : 모든 논리명에 적용됨, 실제 테이블에 적용 spring.jpa.hibernate.naming.physical-strategy ex) 전사적으로 클래스명 앞에 xx를 붙여야할 때

  6. 캐스케이드 (cascade=CascadeType.ALL) 원래는 엔티티 각각에 대해 persist해야한다. 하지만 캐스케이드를 추가하면 컬렉션에 있는 데이터들 또는 그 엔티티를 모두 함께 다 persist해준다! Order 클래스(테이블) 내에서 orderItems 추가할 때 엔티티 각각에 대해 persist해야한다. 다음과 같이 : persist(orderItemA) persist(orderItemB) persist(orderItemC) persist(order) 그런데 orderItems 컬렉션에 @OneToMany(mappedBy="order", cascade=CascadeType.ALL) 추가해주면 persist(order) 이렇게만 해주면 된다.

  7. 양방향 관계일 때 연관관계 편의 메서드 DB 상에서는 한 테이블에서만 데이터 수정 일어나지만 코드상에서 비즈니스 로직구현할 때는 다음처럼 구현할 것이다. 하지만 member, order 둘다 해줘야하는데 한쪽만 하는 경우가 발생하게 된다.

public static void main(String[] args) {
    Member member = new Member();
    Order order = new Order();
    
    member.getOrders().add(order);
    order.setMember(member);
}

다음과 같이 Order 클래스 내에서 원자적으로(두 개 동시에 한번에 묶어서!) 처리하는 메서드를 구현하면 된다! Order 클래스 내에서 Member, OrderItem, Delivery 한번에 처리한다. (Order&Member, ORder&OrderItem, Order&Delivery)

다음과 같은 메서드는 양방향 중에 핵심적으로 컨트롤을 하는 쪽에 구현하는 것이 좋다!

public void setMember(Member member) {
    this.member = member;
    member.getOrders().add(this);
}

public void addOrderItem(OrderItem orderItem) {
    orderItems.add(orderItem);
    orderItem.setOrder(this);
}

public void setDelivery(Delivery delivery) {
    this.delivery = delivery;
    delivery.setOrder(this);
}

Last updated