JPA #1 - 엔티티 설계와 주의사항
업데이트:
JPA 학습
프로젝트 환경설정
강의 정보
- 실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
- 김영한
프로젝트
- JPA란? 강력한 JAVA ORM 표준
- 도메인 모델 설계 - 엔티티 설계 - 테이블 설계 - JPA ORM으로 맵핑 - 애플리케이션 아키텍처 구성 - 핵심 비즈니스 로직 개발
JPA와 DB 설정, 동작확인
-
yml 사용방법
-
@Transactional이 Test case에 있으면 작업 후 DB를 롤백한다. -
롤백을 원치않는다면
@Rollback(false)사용하여 커밋할 수 있다. -
하나의 트랜잭션에서 같은 영속성 컨텍스트에서 식별자가 같으면 같다고 인식한다. (1차 캐시에서 있는 값 사용)
-
실제 쿼리문에 어떤 파라미터가 입력되는 지 확인하고 싶을 때 아래 항목 추가한다.
logging: level: org.hibernate.SQL: debug org.hibernate.type: trace
도메인 분석 설계
연관관계 매핑 분석
- 일대다, 다대일 양방향 관계에서는 외래키가 있는(1:N에서 N 부분) 엔터티를 주인으로 정하는 것이 좋다. 연관관계의 주인쪽의 값을 세팅해야 값이 변경된다.(외래 키가 있는 곳이 연관관계의 주인으로 하는 것이 정석. 관리 및 유지보수 측면에서 편하다.)
- 일대다에서 일 부분에 있는
mappedBy는 단순히 읽기만 하는 역할(즉, 단순 조회용)이며, 연관관계의 주인쪽에 세팅을 해야 값이 변경된다. - 외래키가 가까운 곳에 있는 것을 연관관계의 주인으로 정하는 것이 좋다.
- 다대다 관계에서는
@ManyToMany사용은 권장되지 않고 1:N + N:1로 풀어내는 것이 권장된다.
엔터티 클래스 개발
- Enum Type 사용 시
@Enumerated(EnumType.STRING)을 사용하여 Enum 중간에 값이 들어와도 순서가 밀리지 않도록 방지한다.@Enumerated(EnumType.ORDINAL)을 사용하면 순서에 따라 숫자로 맵핑되는데 순서가 중간에 추가되거나 달라지면 장애 문제가 발생한다. - 실무에서
getter는 실용적인 관점에서 많이 사용하여 열어 놓기도 하지만,setter의 경우는 열어놓지 않고 필요한 경우 비즈니스 메서드를 만드는 것이 추후 유지보수 측면에서 훨신 좋다. setter를 제거하고, 생성자에서 값을 모두 초기화해서 변경 불가능한 클래스로 만들도록 하자. 자바에서 리플렉션 같은 기술이 필요한 비어있는 기본 생성자는protected로 설정하자.- 테이블의 아이디는
@Column(name = "table_id")로 설정하는 것이 f.k와 일치성도 있고, DB관리 입장에서 편하다.
엔터티 설계시 주의점
-
Entity에서는 가급적 Setter를 사용하지 말자. 변경포인트가 많아서 유지보수가 어렵다.
-
모든 연관관계는 지연로딩으로(lazy loading) 설정한다.
-
즉시로딩(Eager)은 예측이 어렵고, 어떤 SQL이 실행될지 추적하기 어렵다. 특히 JPQL을 실행할 때 N+1 문제가 자주 발생한다.
-
연관된 에터티를 함께 DB에서 조회해야 하면, fetch join 또는 엔터티 그래프 기능을 사용한다.
-
@XToOne(OneToOne, ManyToOne) 관계는 기본이
EAGER(즉시로딩)이므로 지연로딩으로 설정해야 한다. -
연관관계에서 Lazy Loading 하지 않으면, N+1 문제가 발생 할 수 있다.
-
아래와 같은 상황에서 1개의 order 조회 시 연관관계인 100개의(N개) member가 같이 조회 될 수 있다. (order가 100개라면 100* 100(N) 쿼리가 요청됨)
publlic class Order { @ManeyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "member_id") private Member member; } -
그렇다면 order에서 member를 한번에 가져오고 싶다면?
fetch join또는엔터티 그래프기능을 사용한다.
-
-
컬렉션은 필드 레벨에서 초기화 하는 것이 안전하다.
@OneToMany(mappedBy = "member") private List<Order> orders = new ArrayList<>();null문제에서 안전하다.Hibernate는 엔터티를 영속화 할 때, 컬렉션을 감싸서Hibernate가 제공하는 내장 컬렉션으로 변경된다. 임의의 메서드에서 잘못 생성하면Hibernate내부 메커니즘에 문제가 발생 할 수 있다.
-
cascade = CascadeType.ALL연관된 컬럼을 한번에 관리한다. 저장, 삭제 시 동시에 업데이트 된다.-
아래의 경우 order 변경 시 연관되어있는 orderItems도 전부 업데이트 된다.
publlic class Order { @OneToMany(mappedBy = "order", cascade = CascadeType.ALL) private List<OrderItem> orderItems = new ArrayList<>(); }
-
-
연관관계 편의 메서드는 연관관계의 주인이 되는 쪽에 있으면 편하다.
학습 키워드
@PersistenceCopntext: EntityManage@Inheritance(strategy = InheritanceType.SINGLE_TABLE)@DiscriminatorColumn(name = "dtype"),@DiscriminatorValue("")
댓글남기기