오봉이와 함께하는 개발 블로그
JPA 활용 1 - 엔티티 설계시 주의점 본문
728x90
엔티티 설계시 주의점
엔티티에는 가급적 Setter를 사용하지 말자
Setter가 모두 열려있다. 변경 포인트가 너무 많아서, 유지보수가 어렵다. 나중에 리펙토링으로 Setter 제거하자.
모든 연관관계는 지연로딩으로 설정
@ManyToOne(fetch = FetchType.LAZY)
- 즉시로딩(
EAGER
)은 예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어렵다.- 즉시로딩을 하면 연관된 테이블을 모두 조회하는 것이다.
- 예를 들어 Member를 조회하면 Order를 조회하고 Order와 연관된 모든 테이블을 모두 다 조회한다.
- 특히 JPQL을 실행할 때 N+1 문제가 자주 발생한다.
- 즉시로딩을 하면 연관된 테이블을 모두 조회하는 것이다.
- 실무에서 모든 연관관계는 지연로딩(
LAZY
)으로 설정해야 한다. - 연관된 엔티티를 함께 DB에서 조회해야 하면, fetch join 또는 엔티티 그래프 기능을 사용한다.
- @XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩이므로 직접 지연로딩으로 설정해야 한다.
컬렉션은 필드에서 초기화 하자.
private List<Order> orders = new ArrayList<>();
- 컬렉션은 필드에서 바로 초기화 하는 것이 안전하다.
- null문제에서 안전하다.
- 하이버네이트는 엔티티를 영속화 할 때, 컬랙션을 감싸서 하이버네이트가 제공하는 내장 컬렉션으로 변경한다.
- 만약 getOrders() 처럼 임의의 메서드에서 컬력션을 잘못 생성하면 하이버네이트 내부 메커니즘에 문제가 발생할 수 있다.
- 따라서 필드레벨에서 생성하는 것이 가장 안전하고, 코드도 간결하다.
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.internal.PersistentBag
테이블, 컬럼명 생성 전략
스프링 부트에서 하이버네이트 기본 매핑 전략을 변경해서 실제 테이블 필드명은 다르다.
- https://docs.spring.io/spring-boot/docs/2.1.3.RELEASE/reference/htmlsingle/#howto-configure-hibernate-naming-strategy
- http://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#naming
하이버네이트 기존 구현: 엔티티의 필드명을 그대로 테이블의 컬럼명으로 사용(SpringPhysicalNamingStrategy
)
스프링 부트 신규 설정 (엔티티(필드) 테이블(컬럼))
- 카멜 케이스 -> 언더스코어(memberPoint -> member_point)
- .(점) -> _(언더스코어)
- 대문자 -> 소문자
cascade
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();
JPA를 사용할 때 저장을 하고 싶으면 엔티티마다 persist
를 해야 하는데 CascadeType.ALL
를 적용하면 엔티티마다 persist
하지 않아도 연관된 테이블 모두 persist
된다.(delete
도 마찬가지)
연관관계 편의 메소드
// 연관관계 편의 메소드
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);
}
member.getOrdes().add(order);
order.setMember(member);
->
public void setMember(Member member) {
this.member = member;
member.getOrders().add(this);
}
객체 상태의 양방향 연관관계에서는 두 엔티티에서 조회 등의 용이성을 위해 값을 양쪽 엔티티 모두에 값을 넣어줘야 한다. (물론 DB에는 한 테이블에만 저장)
하지만 잊어버리고 한쪽에만 값을 넣을 수 있기 때문에 편리하게 할 수 있도록 편의 메소드를 만들어 주는 것이 좋다.
연관관계 편의 메소드의 위치는 연관관계 주인이 들고 있는 것이 좋다.
출처 : 인프런 김영한 지식공유자님 강의 - 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
728x90
'BE > JPA' 카테고리의 다른 글
JPA 활용 2 - 회원 등록 API (0) | 2022.09.03 |
---|---|
JPA 활용 1 - 변경 감지와 병합(merge) (0) | 2022.09.03 |
JPA 활용 1 - 엔티티 클래스 개발 (0) | 2022.09.02 |
JPA 활용 1 - 도메인 모델과 엔티티 설계 (0) | 2022.09.02 |
JPA - 벌크 연산 (0) | 2022.07.06 |
Comments