[JPA] μν°ν° ν΄λμ€μ @NoArgsConstructor(access = AccessLevel.PROTECTED)
λ₯Ό λΆμ΄λ μ΄μ
νκ·Έ: JPA
μΉ΄ν κ³ λ¦¬: JPA
μν°ν° ν΄λμ€μ @NoArgsConstructor(access = AccessLevel.PROTECTED)
λ₯Ό λΆμ΄λ μ΄μ
JPA λ₯Ό μ¬μ©νλ€λ³΄λ©΄ Entity ν΄λμ€μ
@NoArgsConstructor(access = AccessLevel.PROTECTED)
λ₯Ό λΆμ¬μ κΈ°λ³Έ μμ±μμ μμ± λ²μλ₯Ό μ ννλ κ²½μ°κ° μλλ° μ κ΅³μ΄ protected λ₯Ό λΆμ΄λμ§, λ€λ₯Έ μ κ·Ό μ νμλ μ μλλμ§μ λν΄ μμ보μ.
μ§μ°λ‘λ©κ³Ό νλ‘μ κ°μ²΄
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
@Entity
@Table(name = "orders")
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // μμ± λ©μλ(createOrder) λ₯Ό ν΅ν΄μλ§ μν°ν°λ₯Ό λ§λ€λλ‘νλ€.
public class Order {
@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<>();
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "delivery_id")
private Delivery delivery;
private LocalDateTime orderDate;
@Enumerated(EnumType.STRING)
private OrderStatus status;
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);
}
/**
* κ°μ²΄ μμ± static factory method
*
*/
public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems) {
Order order = new Order();
order.setMember(member);
order.setDelivery(delivery);
for (OrderItem orderItem : orderItems) {
order.addOrderItem(orderItem);
}
order.setStatus(OrderStatus.ORDER);
order.setOrderDate(LocalDateTime.now());
return order;
}
...
}
JPA μμ λ€λμΌ μ°κ΄κ΄κ³λ₯Ό λ§Ίμλ λΆνμν μΏΌλ¦¬κ° μμ±λλ κ²μ λ°©μ§νκΈ° μν΄ @ManyToOne(fetch = FetchType.LAZY)
λ‘ μ§μ°λ‘λ©μ νκ²λλλ°
FetchType.EAGER
μ λ¬λ¦¬ μ€μ λ‘ find ν Order κ°μ²΄μμ member λ₯Ό νμνλ μμ μ member λ₯Ό 쿼리νκ² λλ€.
1
2
Order findOrder = em.find(Order.class, id); // 1
findOrder.getMember().getName(); // 2
μ μ½λμμ getMember().getName()
μ νΈμΆνλ μμ μ μ€μ λ‘ select * from member where memberId = ?
μΏΌλ¦¬κ° μ€νλλ€.
μ¦, μ΅μ΄ findOrder λ§ μ‘°νν μν(1λ²) μΌλλ Order μν°ν° μμ member μν°ν°κ° μλ€λ μλ―Έκ° λλ€.
κ·Έλ¬λ κ·Έλ κ² λλ κ²½μ° μ μ½λλ NullPointerException μ€λ₯κ° λ°μν κ²μ΄λ€. null μλ€κ° getName() μ λΆκ°λ₯νκΈ° λλ¬Έ. JPA λ μ΄λ° μν©μ λ°©μ§νκΈ° μν΄ Lazy λ‘λ©μ λμμ΄ λλ Member μν°ν°λ₯Ό κ°μΈλ νλ‘μ κ°μ²΄λ₯Ό λ§λ€μ΄ μ°μ findOrder κ°μ²΄λ₯Ό λ§λ λ€.
νλ‘μ κ°μ²΄
νλ‘μ κ°μ²΄λ λ΄λΆμ Member μν°ν°λ₯Ό κ°μ§κ³ μλλ°, getName() μΌλ‘ μ€μ κ·Έ μν°ν°λ₯Ό νΈμΆνλ μμ μ DB μ μΏΌλ¦¬κ° λ μκ°κ³ , Member μν°ν°μ κ°μ΄ μ±μμ§λ€.
μλ§λ μ΄λ member.setName("AAA")
λ±κ³Ό κ°μ΄ Member μν°ν°μ κ°μ μ±μ 1μ°¨ μΊμμ μ μ₯νκ² λ ν
λ°,
λ°νμ νκ²½μμ member μν°ν° κ°μ²΄λ₯Ό μμ±νκΈ° μν΄ λ¦¬νλ μ
μ μ¬μ©νκ² λλ κ²½μ° κΈ°λ³Έ μμ±μκ° νμνλ€. (μ΄λ JPA λΏλ§ μλλΌ Mybatis μμ 쿼리λ₯Ό VO μ 맀ννλ κ²½μ°μλ λ§μ°¬κ°μ§λ€.)
μ¦, νλ‘μ κ°μ²΄λ‘ λ‘λ©λλ μν°ν°μ @NoArgsConstructor(access = AccessLevel.PRIVATE)
κ°μ΄ μΈλΆμμ μμ±μλ₯Ό μ¬μ©ν μ μλ κ²½μ°μ μ μ΄μ μ€λ₯κ° λ°μνλ€.
μμ±μ μ κ·Ό μ νμλ public, protected λ§ κ°λ₯νλ€
μ 리νμλ©΄ JPA μμ μν°ν°λ Public μ΄κ±°λ Protected μμ±μλ§μ κ°μ Έμ νλ€.
β οΈ μν°ν° κ°μ κΈλ‘λ² λ‘λ© μ λ΅(lazy / eager) μ΄ μλλΌ νΉμ λ‘μ§μμ νμν 쿼리(ex. findAll() κ°μ 리μ€νΈ μ‘°ν 쿼리)λ JPQL λ‘ μμ±νκ² λλ€. JPQL μ κ²½μ°μ λ°λ‘ DB λ‘ μΏΌλ¦¬κ° λ μκ°κΈ° λλ¬Έμ κΈλ‘λ² μν°ν° λ‘λ© μ λ΅μ μν₯λ°μ§ μμ. μ΄λ° κ²½μ°μ @ManyToOne κ΄κ³λ fetch join μΌλ‘ κ°μ Έμ€κ³ , @OneToMany κ΄κ³λ batch size μ€μ μ ν΅ν΄ in() μΏΌλ¦¬λ‘ κ°μ Έμ€λ©΄ 쿼리 νΈμΆ νμλ₯Ό μ΅μν ν μ μλ€.
@NoArgsConstructor(access = AccessLevel.PUBLIC)
μΌλ‘ μ€μ νλ©΄ μλλ?
κΈ°λ³Έ μμ±μμ μ κ·Ό μ§μ μκ° Public μ΄κ±°λ Protected μ΄μ¬μΌ νλ μ΄μ λ μκ² λλ°,
κ·ΈλΌ @NoArgsConstructor
λ‘ μ°λ건(Public) μ΄λ€ λ¬Έμ κ° μλ?
μ΄ κ²½μ°λ κΈ°λ₯μμ λ¬Έμ κ° μλλΌ ν΄λ¨Ό μλ¬λ₯Ό λ°©μ§νκΈ° μν¨μ΄λ€.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Transactional
public Long order(Long memberId, Long itemId, int count) {
// μν°ν° μ‘°ν
Member member = memberRepository.findOne(memberId);
Item item = itemRepository.findOne(itemId);
// λ°°μ‘μ 보
Delivery delivery = new Delivery();
delivery.setAddress(member.getAddress());
delivery.setStatus(DeliveryStatus.READY);
// μ£Όλ¬Έμν μμ±
OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(), count);
// μ£Όλ¬Έ μμ±
Order order = Order.createOrder(member, delivery, orderItem);
// μ£Όλ¬Έ μ μ₯
orderRepository.save(order);
return order.getId();
}
μμ κ°μ λΉμ¦λμ€ λ‘μ§μμ μ£Όλ¬Έμνκ³Ό μ£Όλ¬Έ μν°ν°λ₯Ό λ§λ€λ μ μ ν©ν 리 λ©μλλ₯Ό μ΄μ©ν΄ κ°μ²΄λ₯Ό λ§λ€μ΄λ΄κ³ μλ€.
1
2
3
4
5
6
7
8
9
10
11
12
// Order Entity
public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems) {
Order order = new Order();
order.setMember(member);
order.setDelivery(delivery);
for (OrderItem orderItem : orderItems) {
order.addOrderItem(orderItem);
}
order.setStatus(OrderStatus.ORDER);
order.setOrderDate(LocalDateTime.now());
return order;
}
Order μν°ν° λ΄λΆμ κ°μ²΄λ₯Ό λ§λλ λ©μλλ₯Ό λλκ³ μλΉμ€ κ³μΈ΅μμ μν°ν°κ° νμν κ²½μ° μ΄ λ©μλλ₯Ό νΈμΆνλλ‘ νλ€. μ΄λ κ² νλ μ΄μ λ μν°ν°μ κ΄λ ¨λ λ©μλλ₯Ό ν ν΄λμ€μ λͺ¨μλμμΌλ‘μ¨ μμ§λκ° μ¬λΌκ°κ³ , κ°μ΄ μμ νκ±°λ λ€λ₯Έ μ¬λμ΄ μ μ§λ³΄μλ₯Ό νλ κ²½μ° μΈλΆμμ κ°μ²΄ μμ±μ λ°©μ§νλλ°μ λͺ©μ μ΄ μλ€.
λ°λΌμ μλΉμ€ κ³μΈ΅μμ new Order()
λ₯Ό νμ΄ννλ μκ° μ»΄νμΌ μλ¬λ₯Ό λ§λκ² λλ€. λ§μ½ κ°μ²΄μμ±μ λ§μ§ μμΌλ©΄, μ΄λμλ κ°μ²΄μ κ°μ΄ λ³κ²½λ μ μκ³ μ΄λ₯Ό μΆμ νκΈ° νλ€λ€.
μ΄λ κ² μν°ν° μμ λΉμ¦λμ€ λ‘μ§μ ꡬμ±νλ λ°©μμ λλ©μΈ λͺ¨λΈ ν¨ν΄(Domain Model Pattern) μ΄λΌκ³ νκ³ , λ°λλ‘ μν°ν°μ λΉμ¦λμ€ λ‘μ§μ΄ μκ³ μλΉμ€ κ³μΈ΅μ μλ κ²½μ°λ₯Ό νΈλμμ μ€ν¬λ¦½νΈ ν¨ν΄(Transaction Script Pattern) μ΄λΌκ³ νλ€.
μ 리
- νλ‘μ κ°μ²΄ μμ± μ κΈ°λ³Έ μμ±μκ° νμνκΈ° λλ¬Έ
- κ°μ²΄ μμ± λ©μλλ₯Ό ν΅ν΄μλ§ κ°μ²΄λ₯Ό μμ±νλλ‘ κ°μ νκΈ° μν¨
λκΈλ¨κΈ°κΈ°