본문 바로가기
Framework and Tool/JPA

JPA - 고급맵핑 - 요구사항 분석과 맵핑4

by ocwokocw 2021. 7. 18.

- 참조: 자바 ORM 표준 JPA 프로그래밍

- Fetch 설정

기억을 되살리기 위해 우리가 요구사항 분석과 맵핑3 까지 작성했던 UML 을 다시 한번 살펴보자.

클래스 간의 연관관계의 다중성을 JPA 코드로 작성할 때 별다른 Fetch 전략을 작성하지 않았었다. 만약 Project 팀에서 기본 전략을 지연 로딩으로 설정하기로 합의했다면 Fetch 를 설정해줘야 한다. 

 

Default 설정으로 @OneToMany, @ManyToMany 는 지연 로딩으로 설정되어있으므로 @OneToOne, @ManyToOne 을 설정해주자. 주문(Order) 와 주문 상품(Order Item) 의 @OneToOne, @ManyToOne 이 대상이다.

 

@Entity
@Table(name = "ORDERS")
public class Order extends DateMarkable{

	@Id
	@GeneratedValue
	@Column(name = "ORDER_ID")
	private Long id;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "MEMBER_ID")
	private Member member;
	
	@OneToMany(mappedBy = "order")
	private List<OrderItem> orderItems = new ArrayList<>();
	
	@Temporal(TemporalType.TIMESTAMP)
	private Date orderDate;
	
	@Enumerated(EnumType.STRING)
	private OrderStatus status;

	@OneToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "DELIVERY_ID")
	private Delivery delivery;

..........

@Entity
public class OrderItem extends DateMarkable{

	@Id
	@GeneratedValue
	@Column(name = "ORDER_ITEM_ID")
	private Long id;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ORDER_ID")
	private Order order;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "ITEM_ID")
	private Item item;
	
	private int orderPrices;
	private int count;

 

Order 엔티티와 OrderItem 엔티티에서 상대방이 ~ToOne 인 다중성들의 fetch 옵션을 LAZY 로 설정해준다. 사용법은 이처럼 속성의 값만 설정해주면 되므로 간단하다. 

 

중요한것은 비즈니스를 파악해서 요구사항에 따라 자주 함께 사용되는 경우와 그렇지 않은 경우를 구분하고, 즉시 로딩으로 설정했을 때 연관된 엔티티들이 같이 조회되어서 성능에 영향을 미치는지를 판단할 수 있는가라는 점이다.


- 영속성 전이 설정

아래와 같은 테스트코드가 있다고 가정해보자.

public static void save(EntityManager em) {
	
	EntityTransaction tx = em.getTransaction();
	tx.begin();
	
	Delivery delivery = new Delivery();
	em.persist(delivery);
	
	OrderItem orderItem = new OrderItem();
	OrderItem orderItem2 = new OrderItem();
	em.persist(orderItem);
	em.persist(orderItem2);
	
	Order order = new Order();
	order.addOrderItem(orderItem);
	order.addOrderItem(orderItem2);
	em.persist(order);
	
	tx.commit();
	em.close();
}

 

연관관계를 맺을 때에는 persist 로 해당 엔티티의 영속화를 먼저 진행한다. 이렇게 코드를 작성하다보면 비즈니스 로직에 온전히 집중하기 보다 연관을 맺기전에 영속화를 먼저 해주어야 한다라는 기술적인 측면이 코드에 개입되는것을 느낄 수 있다.

 

영속성 전이를 사용하여 부모 엔티티를 영속화시키면 전이가 일어나서 참조 엔티티들도 영속화되도록 설정해주자. Order 의 영속성 전이 설정 부분을 아래와 같이 설정해주자.

 

@Entity
@Table(name = "ORDERS")
public class Order extends DateMarkable{

	@Id
	@GeneratedValue
	@Column(name = "ORDER_ID")
	private Long id;
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "MEMBER_ID")
	private Member member;
	
	@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
	private List<OrderItem> orderItems = new ArrayList<>();
	
	@Temporal(TemporalType.TIMESTAMP)
	private Date orderDate;
	
	@Enumerated(EnumType.STRING)
	private OrderStatus status;

	@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	@JoinColumn(name = "DELIVERY_ID")
	private Delivery delivery;

 

orderItems 필드와 delivery 필드에서 CASCADE 를 ALL 로 설정하였다. 주문이 없다면 해당 주문에서 어떤 상품을 주문했느냐를 표현하는 OrderItem 엔티티는 삭제되어도 무방하다. 또한 해당 주문에 대한 배송지를 표현하는 Delivery 엔티티도 주문이 삭제된다면 같이 삭제되어도 무방하다. 다만 회원은 주문이 존재하지 않아도 존재할 수 있으므로 CASCADE 설정을 해주면 안된다.

 

public static void save(EntityManager em) {
	
	EntityTransaction tx = em.getTransaction();
	tx.begin();
	
	Delivery delivery = new Delivery();
	
	OrderItem orderItem = new OrderItem();
	OrderItem orderItem2 = new OrderItem();
	
	Order order = new Order();
	order.setDelivery(delivery);
	order.addOrderItem(orderItem);
	order.addOrderItem(orderItem2);
	em.persist(order);
	
	tx.commit();
	em.close();
}

 

테스트코드도 위와 같이 persist 로 설정해줘야 하는 부분이 확연히 줄어든다. Delivery 와 OrderItem 의 연관만 신경쓰고 마지막에 Order 엔티티만 영속화하면 전이가 일어난다.

데이터도 위와 같이 잘 저장되는것을 알 수 있다.

'Framework and Tool > JPA' 카테고리의 다른 글

JPA - 값 타입 - 불변객체  (0) 2021.07.22
JPA - 값 타입 - 임베디드 타입  (0) 2021.07.20
JPA - 영속성 전이와 고아 객체  (0) 2021.07.17
JPA - 지연 로딩  (0) 2021.07.16
JPA - 즉시 로딩과 지연 로딩  (0) 2021.07.15

댓글