๋ค๋๋ค ๋งคํ ์ํฐํฐ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํ๋ฉด์
Cascade ํ์ ์ ์ค์ ํ๋ค.
Cascade๊ฐ ๋ฌด์์ด๋ฉฐ ์ด๋ค ์ข ๋ฅ๊ฐ ์๋์ง ์ดํด๋ณด์.
1. Cascade
- ์์์ฑ์ ์์ฑ๋ ๋ฐ์ดํฐ๋ ๊ฐ์ฒด๊ฐ ํ๋ก๊ทธ๋จ์ ์ข ๋ฃํ๊ฑฐ๋ ์์คํ ์ด ์ฌ๋ถํ ๋์ด๋ ์ฌ๋ผ์ง์ง ์๊ณ ์๊ตฌ์ ์ผ๋ก ์ง์๋๋ ํน์ฑ์ ๋งํ๋ค.
- Cascade๋ ์์์ฑ ์ ์ด๋ก ๋ถ๋ชจ ์ํฐํฐ๊ฐ ์ํํ ์์์ฑ ์์ ์ ์ฐ๊ด๋ ์์ ์ํฐํฐ์๊ฒ๋ ์๋์ผ๋ก ์ ๋ฌํ๋ ๊ธฐ๋ฅ์ด๋ค.
- ์๋ฅผ ๋ค์ด ๋ถ๋ชจ ์ํฐํฐ๋ฅผ ์ ์ฅํ ๋ ์์ ์ํฐํฐ๋ ํจ๊ป ์ ์ฅํ๊ฑฐ๋ ๋ถ๋ชจ ์ํฐํฐ๋ฅผ ์ญ์ ํ ๋ ์์ ์ํฐํฐ๋ ํจ๊ป ์ญ์ ๋๋๋ก ๋ง๋ค ์ ์๋ค.
- JPA์์๋ ์ด๋ฌํ ์ฐ๊ด๋ ์ํฐํฐ๊ฐ์ ์์กด์ฑ์ ์ค์ ํ๊ธฐ ์ํด Enum ํ์ ์ jakarta.persistence.CascadeType์ ์ ๊ณตํ๊ณ ์๋ค. → JPA์์ CascadeType์ ํตํด ์ด๋ค ์์ ์ ์์ ์ํฐํฐ์๊ฒ ์ ์ดํ ์ง ์ค์ ํ ์ ์๋ค๋ ๋ง์ด๋ค.
- ์ฃผ์) ์์ ์ํฐํฐ๊ฐ ๋ถ๋ชจ ํ๋์๊ฒ๋ง ์์ ๋๋ ๊ตฌ์กฐ์ผ ๋ ์ฌ์ฉํ๋ ๊ฒ์ด ์์ ํ๋ค. ๋ง์ฝ ์ฌ๋ฌ ๋ถ๋ชจ์๊ฒ์ ๊ณต์ ๋๋ ์ํฐํฐ์ REMOVE ๊ฐ์ Cascade๋ฅผ ๊ฑธ๋ฉด, ์๋ํ์ง ์์ ๋ฐ์ดํฐ๊น์ง ํจ๊ป ์ญ์ ๋ ์ ์๋ค.
2. CascadeType
- CascadeType.ALL
์๋์ ๋ชจ๋ Cascade ์ค์ ์ ํ ๋ฒ์ ์ ์ฉํ๋ค. - CascadeType.PERSIST
๋ถ๋ชจ ์ํฐํฐ๊ฐ ์์ํ๋ ๋, ์ฐ๊ด๋ ์์ ์ํฐํฐ๋ ํจ๊ป ์์ํ๋๋ค. - CascadeType.REMOVE
๋ถ๋ชจ ์ํฐํฐ๊ฐ ์ญ์ ๋ ๋, ์ฐ๊ด๋ ์์ ์ํฐํฐ๋ ํจ๊ป ์ญ์ ๋๋ค. - CascadeType.MERGE
์ค์์ ์ํ์ ๋ถ๋ชจ ์ํฐํฐ๊ฐ ๋ณํฉ๋ ๋, ์์ ์ํฐํฐ๋ ํจ๊ป ๋ณํฉ๋๋ค. - CascadeType.REFRESH
๋ถ๋ชจ ์ํฐํฐ๊ฐ DB๋ก๋ถํฐ ๊ฐ์ ๋ค์ ์ฝ์ด์ฌ ๋, ์์ ์ํฐํฐ๋ ํจ๊ป ์๋ก๊ณ ์นจํ๋ค. - CascadeType.DETACH
๋ถ๋ชจ ์ํฐํฐ๊ฐ ์์์ฑ ์ปจํ ์คํธ์์ ๋ถ๋ฆฌ(์ค์์ํ)๋ ๋, ์์ ์ํฐํฐ๋ ํจ๊ป ๋ถ๋ฆฌ๋๋ค.
3. Cascade ์ฌ์ฉ์ ๋ํ์ ์ธ ์์
์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ๋๊ตฌ์ผ๊น?
- Order๊ณผ OrderItem
Order 1๊ฐ
โโโ OrderItem ์ฌ๋ฌ ๊ฐ
์ฃผ๋ฌธ ํ๋ ์์ ์ฌ๋ฌ ์ฃผ๋ฌธ์ํ์ด ๋ค์ด๊ฐ๋ค.
Order
โโโ OrderItem: ์ฌ๊ณผ
โโโ OrderItem: ์ฐ์
โโโ OrderItem: ๊ณผ์
์ฌ์ฉ์๊ฐ ์ฌ๊ณผ, ์ฐ์ , ๊ณผ์๋ฅผ ์ฃผ๋ฌธํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
์ฃผ๋ฌธ ์ํฐํฐ
@Entity
public class Order {
// Order๋ฅผ ์ ์ฅํ ๋, OrderItem๋ ํจ๊ป ์ ์ฅ๋๋ค.
@OneToMany(mappedBy = "order", cascade = CascadeType.PERSIST)
private List<OrderItem> orderItems = new ArrayList<>();
// ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ ํธ์ ๋ฉ์๋
// ๋ถ๋ชจ์ ์์์ ๊ด๊ณ๋ฅผ ํ ๋ฒ์ ๋ง์ถฐ์ค๋ค.
public void addOrderItem(OrderItem orderItem) {
orderItems.add(orderItem);
orderItem.setOrder(this);
}
}
@OneToMany(mappedBy = "order", cascade = CascadeType.PERSIST)ํ๋์ ์ฃผ๋ฌธ์๋ ์ฌ๋ฌ ๊ฐ์ ์ฃผ๋ฌธ ์์ดํ ์ด ๋ค์ด๊ฐ ์ ์๋ค. ๊ทธ๋์ Order ์ํฐํฐ์์๋ @OneToMany๋ฅผ ์ฌ์ฉํด OrderItem ๋ชฉ๋ก์ ๊ฐ์ง๋ค.
๋จผ์ ๋ถ๋ชจ ์ํฐํฐ๋ Order, ์์ ์ํฐํฐ๋ OrderItem์ด ๋ง๋ค. ์ฃผ๋ฌธ์ด ์์ด์ผ ์ฃผ๋ฌธ ์์ดํ ์ด ์๋ฏธ๋ฅผ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ด๋ค. ์๋ฅผ ๋ค์ด ์ฌ๊ณผ, ์ฐ์ , ๊ณผ์๋ฅผ ์ฃผ๋ฌธํ๋ค๋ฉด ์ด ์ํ๋ค์ ๋ชจ๋ ํ๋์ ์ฃผ๋ฌธ ์์ ํฌํจ๋๋ค. ๊ทธ๋์ ๊ฐ๋ ์ ์ผ๋ก Order๊ฐ ๋ถ๋ชจ์ด๊ณ , OrderItem์ด ์์์ด๋ค.
๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ์ mappedBy = "order"๋ ์ด ๊ด๊ณ์ ์ฃผ์ธ์ order๊ฐ ์๋ OrderItem ์ํฐํฐ์ order ํ๋๋ผ๊ณ ์๋ฆฌ๊ณ ์๋ค. ์ด๊ฒ์ ๋ ๋ฌด์จ ์ด์ผ๊ธฐ์ผ๊น?
JPA์์ ๋งํ๋ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ๋ถ๋ชจ์ ์์์ ๋ฐ์ง๋ ๊ฐ๋ ์ด ์๋๋ผ, ์ธ๋ ํค๋ฅผ ์ค์ ๋ก ๊ด๋ฆฌํ๋ ์ชฝ์ ๋งํ๋ค. ๊ทธ๋ฌ๋๊น ์์์ฑ ์ ์ด๋ก ๋ดค์๋๋ ๋ถ๋ชจ ์ํฐํฐ๊ฐ Order์ธ๊ฒ ๋ง๊ณ ๊ทธ๊ฑฐ์ ๋ณ๊ฐ๋ก ์ธ๋ํค๋ฅผ ๊ฐ์ง๋ ์ชฝ์ OrderItem์ด๋ผ๊ณ ๋งํ๋ ๊ฒ์ด๋ค. mappedBy๋ ์ด ์ธ๋ํค๋ฅผ ๋๊ฐ ๊ฐ์ง๊ณ ์๋์ง ์ ์ํ๋ค.
์ฃผ๋ฌธ ์์ดํ
์ํฐํฐ
@Entity
public class OrderItem {
// OrderItem ์
์ฅ์์๋ ์์ ์ด ์ด๋ค Order์ ์ํ๋์ง ์์์ผ ํ๋ค.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;
}
ํ ์ด๋ธ์ ์ด๊ณ ๋ณด๋ฉด ๋ ์ฝ๊ฒ ์ ์ ์๋ค. order ํ ์ด๋ธ ์์ orderItem ๋ชฉ๋ก์ด ์ ์ฅ๋๋ ๊ฒ์ด ์๋๋ค. ์ค์ ๋ก๋ order_item ํ ์ด๋ธ ์์ order_id๋ผ๋ ์ธ๋ํค๊ฐ ๋ค์ด๊ฐ๋ค. ์ฆ, ์ด๋ค ์ฃผ๋ฌธ ์์ดํ ์ด ์ด๋ค ์ฃผ๋ฌธ์ ์ํ๋์ง๋ OrderItem ํ ์ด๋ธ์ order_id ๊ฐ์ผ๋ก ์ ํด์ง๋ค. ๊ทธ๋์ JPA์์๋ ์ธ๋ํค๋ฅผ ๊ฐ์ง๊ณ ์๋ OrderItem์ด ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ด ๋๋ค.
๋ค์ ์ ๋ฆฌํ๋ฉด ์ด๋ ๋ค.
Order๊ฐ ๋ถ๋ชจ ์ํฐํฐ๋ผ๊ณ ํด์ ๋ฐ๋์ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ด ๋์ง ์๋๋ค. JPA์์ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ํญ์ ์ธ๋ํค๋ฅผ ๊ด๋ฆฌํ๋ ์ชฝ์ด๊ณ ์ด ์์์์๋ OrderItem์ด ๊ทธ ์ญํ ์ ํ๋ค.
๋ถ๋ชจ ์ํฐํฐ Order ์์ ์ํฐํฐ OrderItem ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ OrderItem
( order_item ํ ์ด๋ธ์ด order_id ์ธ๋ ํค๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ )
์๋น์ค๋ก์ง
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
@Transactional
public void createOrder() {
Order order = new Order();
OrderItem apple = new OrderItem("์ฌ๊ณผ");
OrderItem milk = new OrderItem("์ฐ์ ");
// Order์ OrderItem์ ์ฐ๊ฒฐํ๋ค.
order.addOrderItem(apple);
order.addOrderItem(milk);
// CascadeType.PERSIST ๋๋ถ์ Order๋ง ์ ์ฅํด๋
// ์ฐ๊ฒฐ๋ OrderItem๋ค๋ ํจ๊ป ์ ์ฅ๋๋ค.
orderRepository.save(order);
}
}
@OneToMany(mappedBy = "order", cascade = CascadeType.PERSIST) private List<OrderItem> orderItems = new ArrayList<>();
JPA๋ ์ด ์ฝ๋๋ฅผ ๋ณด๊ณ Order๋ฅผ ์ ์ฅํ ๋, Order ์์ ๋ค์ด์๋ orderItems๋ ๊ฐ์ด ์ ์ฅํ๋ค. cascade = CascadeType.PERSIST๊ฐ Order ์ํฐํฐ ์์ orderItems ํ๋์ ๋ถ์ด ์๊ธฐ ๋๋ฌธ์, Order์์ OrderItem ๋ฐฉํฅ์ผ๋ก ์ ์ฅ ์์ ์ด ์ ์ด๋๋ค.// Order์ OrderItem์ ์ฐ๊ฒฐํ๋ค. order.addOrderItem(apple); order.addOrderItem(milk);
์ด ๋ฉ์๋์ ๋ด๋ถ๋ ์ด๋ ๊ฒ ์ฒ๋ฆฌ๋๋ค.public void addOrderItem(OrderItem orderItem) { // Order ์์ ์ฃผ๋ฌธ ์์ดํ ๋ชฉ๋ก์ ์ถ๊ฐ this.orderItems.add(orderItem); // OrderItem ์ ์ฅ์์๋ ์์ ์ด ์ด๋ค Order์ ์ํ๋์ง ์ ์ฅ orderItem.setOrder(this); }
๊ทธ๋ฌ๋ฉด ๊ฐ์ฒด ์ํ๋ ์ด๋ ๊ฒ ๋๋ค.Order โโโ orderItems โโโ apple → order ์ฐธ์กฐ โโโ milk → order ์ฐธ์กฐ
์ด ์ํ์์orderRepository.save(order);
JPA๋ Order๋ฅผ ๋จผ์ ์ ์ฅํ๋ค. ๊ทธ๋ฐ๋ฐ Order ์์๋ orderItems ํ๋์ cascade = CascadeType.PERSIST ์ค์ ์ด ์์๋ค. ๊ทธ๋ฌ๋ฉด ์ด๊ฑธ ๋ณธ JPA๋ orderItems ์์ ์๋ OrderItems๋ค๋ ๊ฐ์ด ์ ์ฅํ๋ คํ๋ค. ๋ค์ ์ฝ๊ฒ ์ค๋ช ํ์๋ฉด OrderRepository.save(order) ํ์ค๋ง ์์ฑํ๋๋ผ๋ ๋ด๋ถ์์ order ์ ์ฅ - apple ์ ์ฅ - milk ์ ์ฅ์ด ๋๋ค.
Q. ๋ง์ฝ Cascade๋ฅผ ์ฌ์ฉํ์ง ์์๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
A. Cascade๊ฐ ์๋ค๋ฉด ๋น์ฐํ JPA๋ Order๋ง ์ ์ฅํ๋ค. orderRepository.save(order)๋ฅผ ์ ์ผ๋ฉด OrderItem์ ์๋ ์ ์ฅ๋์ง ์๋๋ค. ๊ทธ๋์ ์ง์ ์ ์ฅํด์ค์ผํ๋ค.
orderRepository.save(order); orderItemRepository.save(apple); orderItemRepository.save(milk);