※ 본 포스팅은 김영한 강사님의 인프런 '실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발' 강의를 들으며 작성한 수강일지 입니다.
| 도메인 분석 설계
1. 요구사항 분석
2. 도메인 모델과 테이블 설계
3. 엔티티 클래스 개발1
4. 엔티티 클래스 개발2
5. 엔티티 설계시 주의점
5. 엔티티 설계시 주의점
1) 엔티티에는 가급적 Setter를 사용하지 말자
- Setter가 모두 열려있으면 변경 포인트가 너무 많아서 어디서 어떻게 수정이 되었는지 알기 힘들고 유지보수가 어려움
- 예제에서는 Setter를 열어둠(실무에서는 가급적이면 X)
2) 모든 연관관계는 지연로딩(LAZY)으로 설정하자
- 즉시로딩(EAGER) : member를 조회할 때 연관된 order를 모두 조회하겠다는 것(연관된 모든 데이터를 다 가지고 옴)
예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어려우며 특히 JPQL을 실행할 때 N+1 문제가 자주 발생함
- 실무에서 모든 연관관계는 지연로딩(LAZY)으로 설정해야 함
- 연관된 엔티티를 함께 DB에서 조회해야 하면, fetch join 또는 엔티티 그래프 기능을 사용
- @XToOne(OneToOne, ManyToOne) 관계는 기본이 즉시로딩이므로 직접 지연로딩으로 설정해야 함
cf) OneToMany -> 기본이 LAZY
fetch 전략을 적지 않아도 default 값이 위와 같다
xToMany는 기본이 LAZY이기 때문에 그냥 두면 되고, ManyToOne은 전부 LAZY로 변경해주어야 함
ManyToOne 전부 변경 처리하기위해 검색(Command + Shift + F)
Option(Alt) + Enter -> static import하면 더 깔끔하게 됨
OneToOne도 변경해주기
3) 컬렉션은 필드에서 바로 초기화 하는 것이 안전하다
- null 문제에서 안전함
- Hibernate는 엔티티를 영속화 할 때, 컬렉션을 감싸서 Hibernate가 제공하는 내장 컬렉션으로 변경함
만약 getOrders() 처럼 임의의 메서드에서 컬렉션을 잘못 생성하면 Hibernate 내부 메커니즘에 문제가 생길 수 있음 -> 따라서 필드레벨에서 생성하는 것이 가장 안전하고, 코드도 간결함
Hibernate가 관리하는 컬렉션이 되었으므로, 절대 변경하지 말것
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
4) 테이블, 컬럼명 생성 전략
- 스프링 부트에서 하이버네이트 기본 매핑 전략을 변경해서 실제 테이블 필드명은 다름
[참고2] https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#naming
- Hibernate 기존 구현 : 엔티티의 필드명을 그대로 테이블의 컬럼명으로 사용
(SpringPhysicalNamingStrategy) -> 코드 참고하여 회사 룰에 맞게 변경하여 설정할 수 있음
- 스프링 부트 신규 설정 : 엔티티(필드) -> 테이블(컬럼)
- 카멜 케이스 -> 언더스코어(memberPoint -> member_point)
- .(점) -> _(언더스코어)
- 대문자 -> 소문자
- 적용 2단계
- 논리명 생성 : 명시적으로 컬럼, 테이블명을 직접 적지 않으면 ImplicitNamingStrategy 사용
- spring.jpa.hibernate.naming.implicit-strategy : 테이블이나 컬럼명을 명시하지 않을 때 논리명 적용
- 물리명 적용
- spring.jpa.hibernate.naming.physical-strategy : 모든 논리명에 적용됨, 실제 테이블에 적용
- (username -> usernm 등으로 회사 룰로 바꿀 수 있음)
- 스프링 부트 기본 설정
spring.jpa.hibernate.naming.implicit-strategy:
org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
spring.jpa.hibernate.naming.physical-strategy:
org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
지난 시간에 빠진 내용
1) cascade
- 원래라면 위처럼 persist를 다 써주어야 하는데 Cascade는 persist를 전파하기 때문에 CascadeType.ALL을 써주면
persist(order) 하나만 남기면 됨(ALL로 해두었기 때문에 delete 할 때도 같이 지워버림)
- 원래 모든 엔티티는 저장하고 싶다면 각각 다 persist해주어야 함
2) 연관관계 편의 메서드(연관관계 메서드)
//==연관관계 (편의) 메서드==//
public void setMember(Member member) {
this.member = member;
}
public static void main(String[] args) {
Member member = new Member();
Order order = new Order();
member.getOrders().add(order);
order.setMember(member);
}
- 양방향일 때, 원래대로라면 이렇게 해주어야 하는데 이걸 잊어버릴 수도 있으니 두개를 원자적으로 묶어주는 메서드를 만들기
// 양방향 연관관계 세팅
//==연관관계 (편의) 메서드==// // -> 핵심적으로 control 하는 쪽에 코드가 위치하는 것이 좋음
public void setMember(Member member) {
this.member = member;
member.getOrders().add(this); // 아래 두 과정을 놓칠 수 있으니 이걸 원자적으로 묶어주는 메서드 만들어 넣기
}
// public static void main(String[] args) {
// Member member = new Member();
// Order order = new Order();
//
//// member.getOrders().add(order); // member.getOrders().add(this); 위에 이 코드 덕분에 이 코드는 쓰지 않아도 됨
// order.setMember(member);
// }
// order <-> orderItems도 양방향
public void addOrderItem(OrderItem orderItem) {
orderItems.add(orderItem);
orderItem.setOrder(this);
}
public void setDelivery(Delivery delivery) {
this.delivery = delivery;
delivery.setOrder(this);
}
- 해당 메서드의 위치는 핵심적으로 Control하는 쪽에 위치하는 것이 좋음
//==연관관계 (편의) 메서드==// // -> 양방향이기 때문에 필요 : child를 집어넣으면 양쪽에 다 들어가야 함(부모에도, 자식에도)
public void addChildCategory(Category child) {
this.child.add(child);
child.setParent(this); // 자식에서도 부모가 누군지 this로 넣어 주어야 함
}
'프로그래밍 > spring boot' 카테고리의 다른 글
[스프링부트] 실전! 스프링 부트와 JPA 활용1 #3-2 애플리케이션 아키텍처 (0) | 2023.10.31 |
---|---|
[스프링부트] 실전! 스프링 부트와 JPA 활용1 #3-1 구현 요구사항 (0) | 2023.10.31 |
[스프링부트] 실전! 스프링 부트와 JPA 활용1 #2-4 엔티티 클래스 개발2 (0) | 2023.10.27 |
[스프링부트] 실전! 스프링 부트와 JPA 활용1 #2-3 엔티티 클래스 개발1 (1) | 2023.10.27 |
[스프링부트] 실전! 스프링 부트와 JPA 활용1 #2-2 도메인 모델과 테이블 설계 (0) | 2023.10.26 |