OSIV๋ž€

OSIV(Open Session In View)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ตœ์ดˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ์‹œ์ž‘ ์‹œ์ ๋ถ€ํ„ฐ API ์‘๋‹ต์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€DB ์ปค๋„ฅ์…˜์„ ์œ ์ง€ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ ๋ทฐ์™€ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ง€์—ฐ ๋กœ๋”ฉ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

*ํŠธ๋žœ์žญ์…˜์ด ์‹œ์ž‘ํ• ๋•Œ DB์ปค๋„ฅ์…˜์„ ํš๋“ํ•œ๋‹ค.

 

ํ•˜์ง€๋งŒ  ์ด ์ „๋žต์€ ํฐ ๋‹จ์ ์ด ์žˆ๋Š”๋ฐ,  ๋„ˆ๋ฌด ์˜ค๋žœ ์‹œ๊ฐ„ DB ์ปค๋„ฅ์…˜์„ ์œ ์ง€ํ•จ์œผ๋กœ ์ธํ•ด  ๋ฆฌ์†Œ์Šค ๋ถ€์กฑ ์žฅ์• ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.๋”ฐ๋ผ์„œ ์ƒํ™ฉ์— ๋งž๋Š” OSIV ์ „๋žต์ด ํ•„์š”ํ•˜๋‹ค.

 

OSIV ๋™์ž‘ ๋ฐฉ์‹

jpa์—์„œ๋Š” OSIV์˜ ๊ธฐ๋ณธ๊ฐ’์„ true (์‚ฌ์šฉ)์œผ๋กœ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

 

1. ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ๋‚˜ ์Šคํ”„๋ง ์ธํ„ฐ์…‰ํ„ฐ์—์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

2. ์„œ๋น„์Šค ๊ณ„์ธต์—์„œ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋กœ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•œ๋‹ค.(@Transactional ์–ด๋…ธํ…Œ์ด์…˜์ด ์žˆ๋Š” ๊ณณ)

3. ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•˜๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ํ”Œ๋Ÿฌ์‹œํ•˜์ง€๋งŒ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ข…๋ฃŒ์‹œํ‚ค์ง€๋Š” ์•Š๋Š”๋‹ค, (๋ทฐ, ์ปจํŠธ๋กค๋Ÿฌ๊นŒ์ง€ ์œ ์ง€)

4. ์š”์ฒญ์ด ๋Œ์•„์˜ค๋ฉด ํ”Œ๋Ÿฌ์‹œ๋ฅผ ํ•˜์ง€ ์•Š๊ณ  ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฐ”๋กœ ์ข…๋ฃŒํ•œ๋‹ค.

 

OSIV OFF

OSIV๋ฅผ ๋ˆ ์ƒํƒœ์—์„œ ํŠธ๋žœ์žญ์…˜์ด ๋๋‚˜๋ฉด DB ์ปค๋„ฅ์…˜์„ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ๋‚ญ๋น„ํ•˜์ง€ ์•Š๋Š”๋‹ค.

ํ•˜์ง€๋งŒ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋„ ์ข…๋ฃŒ์‹œ์ผœ ๋ฒ„๋ฆฌ๊ธฐ๋•Œ๋ฌธ์— ๋ทฐ์™€ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ง€์—ฐ๋กœ๋”ฉ์„ ํ• ์ˆ˜์—†๋‹ค.๋”ฐ๋ผ์„œ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ๋ชจ๋“  ์ง€์—ฐ๋กœ๋”ฉ์„ ์ฒ˜๋ฆฌํ•ด์•ผํ•œ๋‹ค.

 

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” OSIV ๋ฅผ ๋‹ค์‹œ ์ผ ๋‹ค๊ฑฐ๋‚˜ , ํŽ˜์น˜ ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๋“ฑ ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์ด ์žˆ์ง€๋งŒ

๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. (์ปค๋งจ๋“œ์™€ ์ฟผ๋ฆฌ ๋ถ„๋ฆฌ)

 

์ปค๋งจ๋“œ์™€ ์ฟผ๋ฆฌ ๋ถ„๋ฆฌ

๋ณดํ†ต ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค๋กœ์ง์€ ํ•œ๋ฒˆ ๊ฐœ๋ฐœํ•˜๋ฉด ์‰ฝ๊ฒŒ ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค.

๋ฐ˜๋ฉด ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ทฐ๋กœ์ง์€ ๊ฐœ๋ฐœ์ด ์‹œ์ž‘๋œ ๋’ค์—๋„ ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐ”๋€Œ๋ฏ€๋กœ ๋‘˜์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์ด ๋‹ค๋ฅด๋‹ค.

 

๋”ฐ๋ผ์„œ ๋‘˜์˜ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์œ ์ง€๋ณด์ˆ˜ ๊ด€์ ์—์„œ ์ถฉ๋ถ„ํžˆ ์˜๋ฏธ์žˆ๋‹ค.

 

ex)

OrderService
OrderService: ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
OrderQueryService: ํ™”๋ฉด์ด๋‚˜ API์— ๋งž์ถ˜ ์„œ๋น„์Šค (์ฃผ๋กœ ์ฝ๊ธฐ ์ „์šฉ ํŠธ๋žœ์žญ์…˜ ์‚ฌ์šฉ)

 

๋‘ ์„œ๋น„์Šค ๋ชจ๋‘ ํŠธ๋žœ์žญ์…˜์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์ง€์—ฐ๋กœ๋”ฉ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

์ปฌ๋ ‰์…˜ ์กฐํšŒ ์ตœ์ ํ™” - 1 ์—์„œ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•œ ํ›„์— DTO๋กœ ๋ณ€ํ™˜์‹œํ‚ค๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•˜์˜€์ง€๋งŒ,

์ด๋ฒˆ ์ฑ•ํ„ฐ์—์„œ๋Š” JPA ์—์„œ DTO๋ฅผ ์ง์ ‘ ์กฐํšŒํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•œ๋‹ค.

 

JPA์—์„œ DTO ์ง์ ‘ ์กฐํšŒ

DTO๋ฅผ ์กฐํšŒํ•  ๋•Œ, ToOne ๊ด€๊ณ„๋“ค์„ ๋จผ์ € ์กฐํšŒํ•˜๊ณ  ToMany ๊ด€๊ณ„๋“ค์€ ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด ์ข‹๋‹ค.ToOne ๊ด€๊ณ„๋ฅผ ๋จผ์ € ์ฒ˜๋ฆฌํ•˜๋Š” ์ด์œ ๋Š” Row  ์ˆ˜์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.ํ•˜์ง€๋งŒ ToMany ๊ด€๊ณ„๋Š” Row์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋ฏ€๋กœ(๋ฐ์ดํ„ฐ ๋ปฅํŠ€๊ธฐ) ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ํŽธ์ด ์ข‹๋‹ค.

 

private List<OrderQueryDto> findOrders() {return em.createQuery(
"select new
jpabook.jpashop.repository.order.query.OrderQueryDto(o.id, m.name, o.orderDate,
o.status, d.address)" +
" from Order o" +
" join o.member m" +
" join o.delivery d", OrderQueryDto.class)
.getResultList();
}

/**
* 1:N ๊ด€๊ณ„์ธ orderItems ์กฐํšŒ
*/

private List<OrderItemQueryDto> findOrderItems(Long orderId) {
return em.createQuery(
"select new
jpabook.jpashop.repository.order.query.OrderItemQueryDto(oi.order.id, i.name,
oi.orderPrice, oi.count)" +
" from OrderItem oi" +
" join oi.item i" +
" where oi.order.id = : orderId",
OrderItemQueryDto.class)
.setParameter("orderId", orderId)
.getResultList();
}

์œ„์˜ ์ฝ”๋“œ์—์„œ findOrder() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ฃผ๋ฌธ๋“ค์„ ๋ชจ๋‘ ์กฐํšŒํ•œ๋‹ค.

์ฃผ๋ฌธ๋“ค์„ ๋ชจ๋‘ ์กฐํšŒํ•˜๋Š” ์ด์œ ๋Š” ์—”ํ‹ฐํ‹ฐ์™€ ์ฃผ๋ฌธ์€ ToOne ๊ด€๊ณ„์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

์ฃผ๋ฌธ ์•„์ดํ…œ๋“ค์€ ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ์—ˆ๋Š” ๋ฐ ์ด ์—ญ์‹œ ์œ„์—์„œ ์„ค๋ช…ํ•œ๋Œ€๋กœ ToMany ๊ด€๊ณ„์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„๋กœ ์ฒ˜๋ฆฌํ•˜์˜€๋‹ค.

 

public List<OrderQueryDto> findOrderQueryDtos() {
//๋ฃจํŠธ ์กฐํšŒ(toOne ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ํ•œ๋ฒˆ์— ์กฐํšŒ)
List<OrderQueryDto> result = findOrders();
//๋ฃจํ”„๋ฅผ ๋Œ๋ฉด์„œ ์ปฌ๋ ‰์…˜ ์ถ”๊ฐ€(์ถ”๊ฐ€ ์ฟผ๋ฆฌ ์‹คํ–‰)
result.forEach(o -> {
List<OrderItemQueryDto> orderItems =
findOrderItems(o.getOrderId());
o.setOrderItems(orderItems);
});
ret

 

์ด๋ ‡๊ฒŒ ์กฐํšŒ๋œ ๊ฒฐ๊ณผ๋“ค์„ DTO์— ๋งคํ•‘์‹œ์ผฐ๋‹ค.

 

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด, id ๋ฅผ ์กฐํšŒํ• ๋•Œ ์ฟผ๋ฆฌ 1๋ฒˆ์ด ๋ฐœ์ƒํ•˜๊ณ  ๊ทธ ๋’ค๋กœ ์ปฌ๋ ‰์…˜์„ ์กฐํšŒํ•  ๋•Œ ์ฟผ๋ฆฌ N๋ฒˆ์ด ๋ฐœ์ƒํ•˜๋ฏ€๋กœ 

1+N ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค. 

๋”ฐ๋ผ์„œ ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

 

JPA์—์„œ DTO ์ง์ ‘ ์กฐํšŒ - ์ปฌ๋ ‰์…˜ ์กฐํšŒ ์ตœ์ ํ™”

๊ธฐ์กด์˜ ๋ฃจํ”„๋ฅผ ๋Œ๋ฉด์„œ ์กฐํšŒํ–ˆ๋˜ ๋ฐฉ์‹์„ Map ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•จ์œผ๋กœ์จ 1+N ๋ฌธ์ œ๋ฅผ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

private Map<Long, List<OrderItemQueryDto>> findOrderItemMap(List<Long>
orderIds) {
List<OrderItemQueryDto> orderItems = em.createQuery(
"select new
jpabook.jpashop.repository.order.query.OrderItemQueryDto(oi.order.id, i.name,
oi.orderPrice, oi.count)" +
" from OrderItem oi" +
" join oi.item i" +
" where oi.order.id in :orderIds", OrderItemQueryDto.class)
.setParameter("orderIds", orderIds)
.getResultList();
return orderItems.stream()
.collect(Collectors.groupingBy(OrderItemQueryDto::getOrderId));
}

๊ธฐ์กด ์ฝ”๋“œ์™€ ๋‹ค๋ฅธ ์ ์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ฃผ๋ฌธId (์‹๋ณ„์ž) ๊ฐ€ ๋‹ด๊ธด ๋ฆฌ์ŠคํŠธ๋ฅผ ๋„˜๊ฒจ์คฌ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ ๊ธฐ์กด ๋ฃจํ”„ ์ฟผ๋ฆฌ๊ฐ€ ์•„๋‹Œ in์ฟผ๋ฆฌ๋ฅผ ํ†ตํ•ด ์•„์ดํ…œ ์ •๋ณด๊ฐ€ ๋‹ด๊ธด ๋ฐ์ดํ„ฐ๋“ค์„ ํ•œ๋ฒˆ์— ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ์ด๋ ‡๊ฒŒ ๋ถˆ๋Ÿฌ์˜จ ๋ฐ์ดํ„ฐ๋“ค์„ Map ์„ ์ด์šฉํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ์— ์ ์žฌํ•œ๋‹ค.

 

result.forEach(o -> o.setOrderItems(orderItemMap.get(o.getOrderId())));

๋งˆ์ง€๋ง‰์œผ๋กœ DTO ์— ๋งคํ•‘์‹œํ‚ฌ ๋•Œ, ์ด๋ฏธ ๋ฉ”๋ชจ๋ฆฌ์— ์ ์žฌ๋˜์žˆ๋Š” ์ƒํƒœ์ด๋ฏ€๋กœ ์ถ”๊ฐ€ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ ๋ฃจํŠธ ์ฟผ๋ฆฌ์—์„œ 1๋ฒˆ , ์ปฌ๋ ‰์…˜ ์กฐํšŒํ•  ๋•Œ 1๋ฒˆ๋งŒ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ 1+N ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

 

JPA์—์„œ DTO๋กœ ์ง์ ‘ ์กฐํšŒ, ํ”Œ๋žซ ๋ฐ์ดํ„ฐ ์ตœ์ ํ™”

์ฟผ๋ฆฌ๋ฅผ ํ•œ๋ฒˆ๋งŒ ๋‚ ๋ ค์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋“ค์„ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ , ์œ„์™€๋Š” ๋‹ค๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋‹ค.

 

public List<OrderFlatDto> findAllByDto_flat() {
return em.createQuery(
"select new
jpabook.jpashop.repository.order.query.OrderFlatDto(o.id, m.name, o.orderDate,
o.status, d.address, i.name, oi.orderPrice, oi.count)" +
" from Order o" +
" join o.member m" +
" join o.delivery d" +
" join o.orderItems oi" +
" join oi.item i", OrderFlatDto.class)
.getResultList();
}

๋จผ์ € ์กฐํšŒํ•  ๋ฐ์ดํ„ฐ๋“ค์„ "๋ชจ๋‘" ๊ฐ€์ ธ์˜จ๋‹ค.

 

public List<OrderQueryDto> ordersV6() {
List<OrderFlatDto> flats = orderQueryRepository.findAllByDto_flat();

return flats.stream()
.collect(groupingBy(o -> new OrderQueryDto(o.getOrderId(),
o.getName(), o.getOrderDate(), o.getOrderStatus(), o.getAddress()),
mapping(o -> new OrderItemQueryDto(o.getOrderId(),
o.getItemName(), o.getOrderPrice(), o.getCount()), toList())
)).entrySet().stream()
.map(e -> new OrderQueryDto(e.getKey().getOrderId(),
e.getKey().getName(), e.getKey().getOrderDate(), e.getKey().getOrderStatus(),
e.getKey().getAddress(), e.getValue()))
.collect(toList());
}

๊ทธ ๋‹ค์Œ ์ด์ฒ˜๋Ÿผ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‹จ๊ณ„์—์„œ API ์ŠคํŽ™์— ๋งž๊ฒŒ ์ถ”๊ฐ€ ์ž‘์—…์„ ํ•ด์ฃผ์–ด์•ผํ•œ๋‹ค.

๋ณด๊ธฐ๋งŒ ํ•ด๋„ ์–ด์ง€๋Ÿฝ๋‹ค ..

 

์ด ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋‹จ์ ์ด ์žˆ๋‹ค.

1. ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ํ•„ํ„ฐ๋ง ์—†์ด ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๋ณต ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.     

    ์ค‘๋ณต ๋ฐ์ดํ„ฐ๊นŒ์ง€ ํ•จ๊ป˜ ๊ฐ€์ ธ์˜ค๋ฏ€๋กœ ์ฟผ๋ฆฌ๋Š” ์ค„์—ˆ์ง€๋งŒ ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์€ ์ €ํ•˜๋  ์ˆ˜ ์žˆ๋‹ค..

2. ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‹จ๊ณ„์—์„œ ์ถ”๊ฐ€ ์ž‘์—…์„ ํ•ด์ค˜์•ผํ•œ๋‹ค. 

3. ํŽ˜์ด์ง•์ด ์•ˆ๋œ๋‹ค!      

    ์ฃผ๋ฌธ ํ•˜๋‚˜(1)๋‹น ์—ฌ๋Ÿฌ๊ฐœ(N)์˜ ๋ฐ์ดํ„ฐ๋“ค์ด ๋”ธ๋ ค์˜ค๋Š”๋ฐ ์—ฌ๊ธฐ์„œ ํŽ˜์ด์ง•์„ ํ•˜๋ฉด (N)์„ ๊ธฐ์ค€์œผ๋กœ ํŽ˜์ด์ง•์ด ๋œ๋‹ค.

 

 

 

 

 

์ผ๋Œ€๋‹ค ๊ด€๊ณ„์ธ ์ปฌ๋ ‰์…˜์„ ํŽ˜์น˜ ์กฐ์ธ์œผ๋กœ ์กฐํšŒํ•  ๋•Œ,

ํ•˜๋‚˜์˜ ์ •๋ณด์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ปฌ๋ ‰์…˜์ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ๊ฐ€ ๋Š˜์–ด๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ ํ™”์— ์–ด๋ ค์›€์ด ์žˆ๋‹ค.

 

๋•Œ๋ฌธ์— ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ์˜ต์…˜์„ ์คŒ์œผ๋กœ์จ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์—”ํ‹ฐํ‹ฐ ์ง์ ‘ ๋…ธ์ถœ

@GetMapping("/api/v1/orders")
public List<Order> ordersV1() {
List<Order> all = orderRepository.findAllByString(new OrderSearch());
for (Order order : all) {
order.getMember().getName(); //Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™”
order.getDelivery().getAddress(); //Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™˜
List<OrderItem> orderItems = order.getOrderItems();
orderItems.stream().forEach(o -> o.getItem().getName()); //Lazy ๊ฐ•์ œ
์ดˆ๊ธฐํ™”
}
return all;
}

LAZY๋กœ๋”ฉ์ด ๋˜์–ด์žˆ๋Š” ํ”„๋ก์‹œ๋ฅผ ๊ฐ•์ œ ์ดˆ๊ธฐํ™”์‹œ์ผœ์ฃผ์–ด์•ผํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์ด ๋ฐฉ๋ฒ•์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง์ ‘ ๋…ธ์ถœ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์— ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋‹ค.

 

์—”ํ‹ฐํ‹ฐ๋ฅผ DTO๋กœ ๋ณ€ํ™˜

public List<OrderDto> ordersV2() {
List<Order> orders = orderRepository.findAll();
List<OrderDto> result = orders.stream()
.map(o -> new OrderDto(o))
.collect(toList());
return result;
}

Order ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜จ ๋’ค OrderDto ๋กœ ๋ณ€ํ™˜์‹œํ‚จ๋‹ค.์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ ์˜์กด์„ ์™„์ „ํžˆ ๋Š์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์ˆœํžˆ Order์— ๋Œ€ํ•œ ์ •๋ณด๋งŒ์ด ์•„๋‹Œ, Item์— ๋Œ€ํ•œ ์ •๋ณด๋„ Dto๋กœ ๋ณ€ํ™˜์‹œํ‚จ๋‹ค.

static class OrderItemDto {
private String itemName;//์ƒํ’ˆ ๋ช…
private int orderPrice; //์ฃผ๋ฌธ ๊ฐ€๊ฒฉ
private int count;
//์ฃผ๋ฌธ ์ˆ˜๋Ÿ‰
public OrderItemDto(OrderItem orderItem) {
itemName = orderItem.getItem().getName();
orderPrice = orderItem.getOrderPrice();
count = orderItem.getCount();
}
}

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ  ๋˜๋ฉด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์ง€์—ฐ๋กœ๋”ฉ์ด ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— 1+N ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

EX) ์ฃผ๋ฌธ 1๊ฐœ ,  ์ฃผ๋ฌธ ์ •๋ณด N๊ฐœ , ์ฃผ๋ฌธ ์ƒํ’ˆ M๊ฐœ ->1 + N + M ๋ฒˆ์˜ ์ฟผ๋ฆฌ ๋ฐœ์ƒ

 

 

์—”ํ‹ฐํ‹ฐ๋ฅผ DTO๋กœ ๋ณ€ํ™˜- ํŒจ์น˜ ์กฐ์ธ ์ตœ์ ํ™”

public List<Order> findAllWithItem() {
return em.createQuery(
"select distinct o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d" +
" join fetch o.orderItems oi" +
" join fetch oi.item i", Order.class)
.getResultList();
}

์ด์ฒ˜๋Ÿผ ํŽ˜์น˜ ์กฐ์ธ์„ ํ†ตํ•ด ์ตœ์ ํ™”๋ฅผ ํ•ด์ฃผ๋ฉด , ์ฟผ๋ฆฌ๊ฐ€ ํ•œ๋ฒˆ๋งŒ ์‹คํ–‰๋จ์œผ๋กœ์จ ๊ธฐ์กด 1+N ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

JPA ์ฟผ๋ฆฌ๋ฌธ์˜ distinct ๋Š” ๋‘ ๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ํ•œ๋‹ค.

1. SQL ์— distinct  ์ถ”๊ฐ€

2. ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ ์ค‘๋ณต ์ œ๊ฑฐ

 

ํ•˜์ง€๋งŒ , ์ด ์ฝ”๋“œ์—์„œ ํŽ˜์ด์ง•์„ ํ•˜๊ฒŒ ๋˜๋ฉด DB๊ฐ€ ์•„๋‹Œ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํŽ˜์ด์ง•์„ ํ•ด๋ฒ„๋ฆฐ๋‹ค.

์ด๊ฒƒ์€ ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ณผ(out of memory)๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๋งค์šฐ ์œ„ํ—˜ํ•œ ํ–‰์œ„์ž„์œผ๋กœ ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

* ์ปฌ๋ ‰์…˜ ํŽ˜์น˜ ์กฐ์ธ์€ 1๊ฐœ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‘˜ ์ด์ƒ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ ๋ถ€์ •ํ•ฉ ๋ฐœ์ƒ

 

 

์—”ํ‹ฐํ‹ฐ๋ฅผ DTO๋กœ ๋ณ€ํ™˜- ํŽ˜์ด์ง• ์ ์šฉ

์•ž์„  ์ฝ”๋“œ์—์„œ ํŽ˜์ด์ง•์ด ์•ˆ๋๋˜ ์ด์œ ๋Š” ์ผ๋Œ€๋‹ค ์กฐ์ธ์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†์ด ์ฆ๊ฐ€(N)ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ ํŽ˜์ด์ง•์„ ํ•˜๊ฒŒ๋˜๋ฉด ํŽ˜์ด์ง• ๊ธฐ์ค€์ด N ์— ๋งž์ถ”์–ด์ง„๋‹ค.

 

๋”ฐ๋ผ์„œ JPA๋Š” ์ด ๊ฒฝ์šฐ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š”๋ฐ ์ด๊ฒƒ์€ ๋งค์šฐ ์œ„ํ—˜ํ•˜๋‹ค !

 

์ผ๋Œ€๋‹ค ๊ด€๊ณ„์—์„œ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๋ฉด ๋œ๋‹ค.

1. ToOne ๊ด€๊ณ„๋Š” ROW ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค์ง€ ์•Š์œผ๋ฏ€๋กœ ํŽ˜์น˜ ์กฐ์ธ์„ ํ•œ๋‹ค.

2. ์ปฌ๋ ‰์…˜์€ ์ง€์—ฐ๋กœ๋”ฉ์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.

3. hibernate.default_batch_fetch_size , @BatchSize ๋ฅผ ์ ์šฉํ•œ๋‹ค. (DB์—์„œ ๋ฏธ๋ฆฌ ๋ถˆ๋Ÿฌ์˜ฌ ๋ฐ์ดํ„ฐ ์ˆ˜)

 

public List<Order> findAllWithMemberDelivery(int offset, int limit) {
return em.createQuery("select o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d", Order.class)
.setFirstResult(offset)
.setMaxResults(limit)
.getResultList();
}
spring:
jpa:
properties:
hibernate:
default_batch_fetch_size: 1000

ToOne ๊ด€๊ณ„๋ฅผ ํ•œ๋ฐฉ์ฟผ๋ฆฌ๋กœ ๊ฐ€์ ธ์˜ค๊ณ  ,  default_batch_fetch_size ๋ฅผ ์„ค์ •ํ•ด์ฃผ๋ฉด, ์„ค์ •ํ•œ ์‚ฌ์ด์ฆˆ๋งŒํผ ์ปฌ๋ ‰์…˜์€ in ์ฟผ๋ฆฌ์— ๋‹ด์•„์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

๋”ฐ๋ผ์„œ ๊ธฐ์กด 1+ N ์ด์—ˆ๋˜ ์ฟผ๋ฆฌ ์ˆ˜๊ฐ€ 1+1 ๋กœ ์ค„์–ด๋“ ๋‹ค. 

 

์‚ฌ์‹ค ToOne ๊ด€๊ณ„๋„ ๊ตณ์ด ํŽ˜์น˜ ์กฐ์ธ ์•ˆํ•ด๋„ ์ƒ๊ด€ ์—†๋Š”๋ฐ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฟผ๋ฆฌ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

 

๋งŒ์•ฝ ์กฐํšŒ ํ•  ๋ฐ์ดํ„ฐ ์ˆ˜๊ฐ€ 2๊ฐœ์ด๊ณ  ์‚ฌ์ด์ฆˆ๋ฅผ 1๋กœ ์„ค์ •ํ–ˆ์œผ๋ฉด , ์ฟผ๋ฆฌ๊ฐ€ ๋‘๋ฒˆ ์‹คํ–‰๋œ๋‹ค. (1 X 2)

๋งŒ์•ฝ ์กฐํšŒ ํ•  ๋ฐ์ดํ„ฐ ์ˆ˜๊ฐ€ 100๊ฐœ์ด๊ณ  ์‚ฌ์ด์ฆˆ๋ฅผ 10์œผ๋กœ ์„ค์ •ํ–ˆ์œผ๋ฉด , ์ฟผ๋ฆฌ๊ฐ€ ์—ด๋ฒˆ ์‹คํ–‰๋œ๋‹ค. (10 X 10)

 

์ด ๋ฐฉ๋ฒ•์€ ํŽ˜์น˜ ์กฐ์ธ์œผ๋กœ ํ–ˆ์„ ๋•Œ ๋ณด๋‹ค ์ฟผ๋ฆฌ๋Š” ์•ฝ๊ฐ„ ๋งŽ์ด ๋ฐœ์ƒํ–ˆ์„์ง€๋Š” ๋ชฐ๋ผ๋„ ๋ฐ์ดํ„ฐ ์ตœ์ ํ™”๊ฐ€ ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์€ ๋” ์ข‹๋‹ค.

ํ•˜์ง€๋งŒ ์†Œ๊ทœ๋ชจ ๋ฐ์ดํ„ฐ์ผ ๊ฒฝ์šฐ ํŽ˜์น˜ ์กฐ์ธ์œผ๋กœ ํ•˜๋Š” ๊ฒŒ ๋” ๋น ๋ฅผ ์ˆ˜ ์žˆ๋‹ค (์ƒํ™ฉ by ์ƒํ™ฉ)

 

 

 

์ด์ „ ๊ฐ•์˜ ๋‚ด์šฉ 

 

์—”ํ‹ฐํ‹ฐ๋ฅผ Request Body ์— ์ง์ ‘ ๋งคํ•‘ํ•  ๊ฒฝ์šฐ ๋ฌธ์ œ์ 

- ์—”ํ‹ฐํ‹ฐ์— ํ”„๋ ˆ์  ํ…Œ์ด์…˜ , API ๊ฒ€์ฆ์„ ์œ„ํ•œ ๋กœ์ง์ด ์ถ”๊ฐ€๋œ๋‹ค. 

  ํ•˜์ง€๋งŒ ์‹ค๋ฌด์—์„œ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ด์šฉํ•œ ์—ฌ๋Ÿฌ API๋“ค์ด ๋งŒ๋“ค์–ด์ง€๋Š”๋ฐ , ๊ฐ๊ฐ์˜ API๋“ค์„ ์œ„ํ•œ ๋ชจ๋“  ์š”์ฒญ์‚ฌํ•ญ๋“ค์„ ๋‹ด๊ธฐ๋Š” ์–ด๋ ต๋‹ค.

  ๋˜ํ•œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด API ์ŠคํŽ™์ด ๋ณ€ํ•œ๋‹ค !

 

- ๋”ฐ๋ผ์„œ ์—”ํ‹ฐํ‹ฐ๋ฅผ Requst Body ์— ์ง์ ‘ ๋งคํ•‘์‹œํ‚ค๋Š” ๊ฒƒ์ด ์•„๋‹Œ , API ๋ฅผ ์œ„ํ•œ DTO๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด์„œ ์ด๊ฒƒ์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์•„์•ผํ•œ๋‹ค.

 

- DTO๋ฅผ ํ†ตํ•ด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์žฅ์ ์ด ์žˆ๋‹ค.

  1. ์—”ํ‹ฐํ‹ฐ์™€ ํ”„๋ ˆ์  ํ…Œ์ด์…˜์„ ์œ„ํ•œ ๋กœ์ง์„ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

       - ์ด์ œ ๋” ์ด์ƒ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—ฌ๋Ÿฌ API๋“ค์„ ์œ„ํ•œ ์š”์ฒญ์‚ฌํ•ญ๋“ค์„ ๋‹ด์„ ํ•„์š”๊ฐ€ ์—†๋‹ค. 

  2. ์—”ํ‹ฐํ‹ฐ์™€ API ์ŠคํŽ™์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

       - ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋„ API ์ŠคํŽ™์ด ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

์ง€์—ฐ๋กœ๋”ฉ๊ณผ ์กฐํšŒ ์„ฑ๋Šฅ ์ตœ์ ํ™”


@GetMapping("/api/v1/simple-orders")
 public List<Order> ordersV1() {
 List<Order> all = orderRepository.findAllByString(new OrderSearch());
 for (Order order : all) {
 order.getMember().getName(); //Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™”
 order.getDelivery().getAddress(); //Lazy ๊ฐ•์ œ ์ดˆ๊ธฐํ™˜
 }
 return all;
 }

API๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ ์œ„์˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž !

์œ„์˜ ์ฝ”๋“œ๋Š” ๋‘ ๊ฐ€์ง€์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

1. ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง์ ‘ ๋…ธ์ถœํ•œ๋‹ค.

2. ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์กฐํšŒํ•˜๋ฏ€๋กœ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

 

์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง์ ‘ ๋…ธ์ถœํ•˜๋Š” ๊ฑฐ๋Š” ๊ทธ๋ ‡๋‹ค์น˜๊ณ  ๋จผ์ € ์˜ˆ์™ธ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผํ•œ๋‹ค.

 

 

์œ„ ์ฝ”๋“œ๊ฐ€ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ์‹์ด fetch.LAZY ์ธ๋ฐ,

JACKSON ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ json์œผ๋กœ ์ƒ์„ฑํ• ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„  ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ๋ชจ๋“ˆ์„ ์„ค์น˜ํ•จ์œผ๋กœ์จ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. 

์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ ์ดˆ๊ธฐํ™”๋œ ํ”„๋ก์‹œ ๊ฐ์ฒด๋งŒ ๋…ธ์ถœํ•˜๊ณ  ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ๋…ธ์ถœ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค.(null๋กœ ๋‚˜์˜ด)

 

๊ทผ๋ฐ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง์ ‘ ๋…ธ์ถœ์‹œํ‚ค๋Š” ๊ฒƒ์€ ๋งค์šฐ ์•ˆ์ข‹๊ธฐ ๋•Œ๋ฌธ์— ์• ์ดˆ์— ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์•ˆ๋œ๋‹ค !

์ฐจ๋ผ๋ฆฌ DTO๋ฅผ ๋ฐ˜ํ™˜์‹œํ‚ค์ž

 

์ฃผ์˜์‚ฌํ•ญ

1. ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง์ ‘ ๋…ธ์ถœํ•  ๋•Œ ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ๊ฑธ๋ฆฐ ๊ณณ์€ ๊ผญ @JsonIgnore ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผํ•œ๋‹ค. (์•ˆํ•˜๋ฉด ๋ฌดํ•œ๋ฃจํ”„ ๊ฑธ๋ฆผ)

2. ์ง€์—ฐ ๋กœ๋”ฉ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค๊ณ  EAGER ๋กœ ๋ฐ”๊พธ๋ฉด ๋” ๊ณจ์น˜์•„ํŒŒ ์ง„๋‹ค.

 

์—”ํ‹ฐํ‹ฐ๋ฅผ DTO๋กœ ๋ฐ˜ํ™˜

@GetMapping("/api/v2/simple-orders")
public List<SimpleOrderDto> ordersV2() {
 List<Order> orders = orderRepository.findAll();
 List<SimpleOrderDto> result = orders.stream()
 .map(o -> new SimpleOrderDto(o))
 .collect(toList());
 return result;
}

@Data
static class SimpleOrderDto {

 private Long orderId;
 private String name;
 private LocalDateTime orderDate; //์ฃผ๋ฌธ์‹œ๊ฐ„
 private OrderStatus orderStatus;
 private Address address;
 public SimpleOrderDto(Order order) {
 orderId = order.getId();
 name = order.getMember().getName();
 orderDate = order.getOrderDate();
 orderStatus = order.getStatus();
 address = order.getDelivery().getAddress();
 }
 
}

 

์ด์ œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ง์ ‘ ๋…ธ์ถœ์‹œํ‚ค๋Š” ๊ฒŒ ์•„๋‹Œ DTO๋ฅผ ๋ฐ˜ํ™˜์‹œํ‚ค๋Š” ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด ์ฝ”๋“œ๋Š” 1+N ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ๋‹ค.

๋กœ๋”ฉ๋ฐฉ์‹์ด fetch.LAZY์ด๋ฏ€๋กœ , order์—์„œ member๋ฅผ ์กฐํšŒํ• ๋•Œ N๋ฒˆ

                                                order์—์„œ Delivery๋ฅผ ์กฐํšŒํ• ๋•Œ N๋ฒˆ ์กฐํšŒ๋œ๋‹ค.(1+N+N)

 

*์ง€์—ฐ๋กœ๋”ฉ์€ ์—ฐ์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ ์กฐํšŒ๋˜๋ฏ€๋กœ , ์ด๋ฏธ ์กฐํšŒ๋œ ๊ฒฝ์šฐ ์ฟผ๋ฆฌ ์ƒ๋žต 

 

ํŽ˜์น˜ ์กฐ์ธ ์ตœ์ ํ™”

public List<Order> findAllWithMemberDelivery() {
 return em.createQuery(
 "select o from Order o" +
 " join fetch o.member m" +
 " join fetch o.delivery d", Order.class)
 .getResultList();
}

1+N ๋ฌธ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํŽ˜์น˜ ์กฐ์ธ์„ ์‚ฌ์šฉํ•ด์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

์›๋ž˜๋Š” member ์™€  delivery ๋ฅผ ๋”ฐ๋กœ ๋”ฐ๋กœ ์กฐํšŒํ–ˆ์ง€๋งŒ ์ด์ œ๋Š” ํ•œ๋ฒˆ์— ์กฐํšŒํ•จ์œผ๋กœ์จ ์กฐํšŒ ์„ฑ๋Šฅ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

(์ง€์—ฐ๋กœ๋”ฉ์ด ๋˜์ง€ ์•Š๋Š”๋‹ค)

 

*ํŽ˜์น˜์กฐ์ธ(fetch join)์ด๋ž€? 

  - jpql์—์„œ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ 

    ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋‚˜ ์ปฌ๋ ‰์…˜์„ ํ•œ๋ฒˆ์— ๊ฐ™์ด ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ DTO ์ง์ ‘ ์กฐํšŒ

public List<OrderSimpleQueryDto> findOrderDtos() {
 return em.createQuery(
 "select new
jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto(o.id, m.name,
o.orderDate, o.status, d.address)" +
 " from Order o" +
 " join o.member m" +
 " join o.delivery d", OrderSimpleQueryDto.class)
 .getResultList();
 }

์ผ๋ฐ˜์ ์ธ SQL๋ฌธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์›ํ•˜๋Š” ๊ฐ’์„ ์„ ํƒํ•ด์„œ ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

select ์ ˆ์—์„œ ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ์„ ํƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋„คํŠธ์›Œํฌ ์šฉ๋Ÿ‰์„ '๊ทผ์†Œํ•˜๊ฒŒ' ์ตœ์ ํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ฒฐ๊ตญ API ์ŠคํŽ™์— ๋งž์ถ˜ ์ฝ”๋“œ๊ฐ€ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ๋“ค์–ด๊ฐ„๋‹ค๋Š” ์ ๊ณผ ํŠน์ • API ๋งŒ์„ ์œ„ํ•œ ๊ฐ’๋งŒ์„ ๋ฐ˜ํ™˜ํ•ด์ค˜์„œ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์žฌ์‚ฌ์šฉ์ด ๋–จ์–ด์ง€๋Š” ๋‹ค๋Š” ์ ์„ ๊ฐ์•ˆํ•ด๋ณด๋ฉด, ํŽ˜์น˜ ์กฐ์ธ๋ณด๋‹ค ๊ฒฐ์ฝ” ์ข‹๋‹ค๊ณ  ํ•  ์ˆ˜๋Š” ์—†๋Š” ๋ฐฉ์‹์ด๋‹ค.

 

๋งŒ์•ฝ ์ด์™€ ๊ฐ™์€ API๋ฅผ ๋งŒ๋“ค์–ด์•ผํ•œ๋‹ค๋ฉด ๋”ฐ๋กœ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

(DTO๋ฅผ ์ง์ ‘ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์€ ํ™”๋ฉด์„ ์œ„ํ•œ ๋กœ์ง์ด๊ธฐ ๋•Œ๋ฌธ)

 

์ •๋ฆฌํ•˜์ž๋ฉด,

๋จผ์ € ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ  ํŽ˜์น˜์กฐ์ธ์œผ๋กœ ์ตœ์ ํ™”๋ฅผ ํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ ๋Œ€๋ถ€๋ถ„ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€๋งŒ ์ถ”๊ฐ€๋กœ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค๋ฉด DTO๋ฅผ ์ง์ ‘ ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•œ๋‹ค.

 

์ด๋ž˜๋„ ์•ˆ๋œ๋‹ค๋ฉด ๋„ค์ดํ‹ฐ๋ธŒ SQL์ด๋‚˜ JDBC ํ…œํ”Œ๋ฆฟ์„ ์ด์šฉํ•ด์„œ SQL์„ ์ง์ ‘ ์‚ฌ์šฉํ•œ๋‹ค. (์ดคํ›„์˜ ๋ฐฉ๋ฒ•)

์—ฐ๊ด€๊ด€๊ณ„ ๋งตํ•‘ ์‹œ ๊ณ ๋ คํ•ด์•ผ ํ•  3๊ฐ€์ง€ 

 

1. ๋‹ค์ค‘์„ฑ 

    ex) ๋‹ค๋Œ€์ผ , ์ผ๋Œ€์ผ 

 

2. ๋‹จ๋ฐฉํ–ฅ , ์–‘๋ฐฉํ–ฅ

   - ํ…Œ์ด๋ธ”์€ ์™ธ๋ž˜ํ‚ค ํ•˜๋‚˜๋กœ ์–‘์ชฝ ์กฐ์ธ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ , ๊ฐ์ฒด๋Š” ์ฐธ์กฐ์šฉ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ๊ณณ์œผ๋กœ๋งŒ ์ฐธ์กฐ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

   - ๋”ฐ๋ผ์„œ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ผ๋Š” ๊ฒƒ์€ ์ฐธ์กฐ์šฉ ํ•„๋“œ๊ฐ€ ์–‘์ชฝ ๋ชจ๋‘ ์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ๋งํ•œ๋‹ค.

 

3. ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ

   - ๊ฐ์ฒด๋Š” ํ…Œ์ด๋ธ”๊ณผ ๋‹ฌ๋ฆฌ ์ฐธ์กฐ๊ฐ€ ๋‘ ๊ตฐ๋ฐ์—์„œ ๋งŒ๋“ค์–ด ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•œ๋‹ค.

   - ์ฐธ์กฐ์šฉ ํ•„๋“œ๊ฐ€ ์–‘์ชฝ์— ์žˆ๋Š” ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„์—์„œ ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•  "์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ"์ด ํ•„์š”ํ•˜๋‹ค.

 

   a. ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ

       - ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.

   b. ์ฃผ์ธ์˜ ๋ฐ˜๋Œ€ํŽธ

       - ์™ธ๋ž˜ํ‚ค์˜ ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ๋‹จ์ˆœ ์กฐํšŒ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค !!

 

์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ข…๋ฅ˜

 

1. ๋‹ค๋Œ€์ผ [n:1]

    - ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค.

1-1 . ๋‹ค๋Œ€์ผ ์–‘๋ฐฉํ–ฅ

    - ์™ธ๋ž˜ํ‚ค๊ฐ€ ์žˆ๋Š” ์ชฝ์ด ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด๋‹ค.

    

2. ์ผ๋Œ€๋‹ค [1:n]

   - ์ผ๋Œ€๋‹ค ๊ด€๊ณ„์—์„œ๋Š” '1' ์ด ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ์ด์ง€๋งŒ ํ…Œ์ด๋ธ”์—์„œ๋Š” n์ด ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์ธ์ด ๋ฐ˜๋Œ€ํŽธ 

     ํ…Œ์ด๋ธ”์˜ ์™ธ๋ž˜ํ‚ค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํŠน์ดํ•œ ๊ตฌ์กฐ๊ฐ€ ๋œ๋‹ค. 

   - ๋”ฐ๋ผ์„œ ์›์น˜์•Š์€ sql๋ฌธ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. (๋ณต์žกํ•œ ์‹ค๋ฌด์—์„œ ์šด์˜์ด ๋งค์šฐ ํž˜๋“ค์–ด์ง„๋‹ค.)

   - ์ด๋Ÿฌํ•œ ํŠน์„ฑ๋•Œ๋ฌธ์— ์ผ๋Œ€๋‹ค๋ณด๋‹ค๋Š” ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„์— ์กฐ๊ธˆ ์†ํ•ด๋ฅผ ๋ณด๋”๋ผ๋„ ๋‹ค๋Œ€์ผ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋กœ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค !

   - @JoinClumn์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ์กฐ์ธํ…Œ์ด๋ธ”(์ค‘๊ฐ„ํ…Œ์ด๋ธ”) ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

 

2.1 ์ผ๋Œ€๋‹ค ์–‘๋ฐฉํ–ฅ

   - ๊ณต์‹์ ์œผ๋กœ ์กด์žฌํ•˜์ง€ ์•Š์ง€๋งŒ ์ฝ๊ธฐ ์ „์šฉ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

@JoinColumn(insertable=false, updatable=false)

    - ์›ฌ๋งŒํ•˜๋ฉด ๋‹ค๋Œ€์ผ ์–‘๋ฐฉํ–ฅ ๊ด€๊ณ„๋ฅผ ์‚ฌ์šฉํ•˜์ž !

 

3. ์ผ๋Œ€์ผ [1:1]

   - ์ผ๋Œ€์ผ ๊ด€๊ณ„์˜ ๋ฐ˜๋Œ€๋„ ์ผ๋Œ€์ผ์ด๋‹ค.

   - ์ฃผ ํ…Œ์ด๋ธ”์ด๋‚˜ ๋Œ€์ƒ ํ…Œ์ด๋ธ”์— ์™ธ๋ž˜ํ‚ค๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

3-1. ์ผ๋Œ€์ผ ์ฃผ ํ…Œ์ด๋ธ” ์™ธ๋ž˜ํ‚ค ๋‹จ๋ฐฉํ–ฅ

   - ๋‹ค๋Œ€์ผ ๋‹จ๋ฐฉํ–ฅ ๋งตํ•‘๊ณผ ์œ ์‚ฌํ•˜๋‹ค

3-2. ์ผ๋Œ€์ผ ์ฃผ ํ…Œ์ด๋ธ” ์™ธ๋ž˜ํ‚ค ์–‘๋ฐฉํ–ฅ

    - ์™ธ๋ž˜ํ‚ค๊ฐ€ ์žˆ๋Š” ๊ณณ์ด ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์ฃผ์ธ์ด๋‹ค.

    - jpa๋งตํ•‘์ด ํŽธ๋ฆฌํ•˜์ง€๋งŒ ์™ธ๋ž˜ํ‚ค์— null์„ ํ—ˆ์šฉํ•ด์•ผํ•œ๋‹ค.

3-3. ์ผ๋Œ€์ผ ๋Œ€์ƒ ํ…Œ์ด๋ธ” ์™ธ๋ž˜ํ‚ค ๋‹จ๋ฐฉํ–ฅ

    - jpa์—์„œ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. 
3-4. ์ผ๋Œ€์ผ ๋Œ€์ƒ ํ…Œ์ด๋ธ” ์™ธ๋ž˜ํ‚ค ์–‘๋ฐฉํ–ฅ

    - 3-2๊ณผ ๋งตํ•‘ ๋ฐฉ๋ฒ•์ด ๊ฐ™๋‹ค.
    - ํ…Œ์ด๋ธ” ๊ด€๊ณ„๋ฅผ ๋ณ€๊ฒฝํ•ด๋„ ํ…Œ์ด๋ธ”์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ , ํ•ญ์ƒ ์ฆ‰์‹œ ๋กœ๋”ฉ์ด ๋œ๋‹ค.(ํ”„๋ก์‹œ ๊ธฐ๋Šฅ์˜ ํ•œ๊ณ„)

4. ๋‹ค๋Œ€๋‹ค [n:n]

     - ๊ด€๊ณ„ํ˜• DB๋Š” ํ…Œ์ด๋ธ” ๋‘๊ฐœ๋กœ ๋‹ค๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์—†์ง€๋งŒ ๊ฐ์ฒด๋Š” ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด์„œ ๋‹ค๋Œ€๋‹ค ๊ด€๊ณ„๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

     - ํ•˜์ง€๋งŒ ๋‹ค๋Œ€๋‹ค ๋งตํ•‘์„ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ๋ถ€๊ฐ€ ์ •๋ณด๋“ค์ด ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”์— ๋“ค์–ด์˜ฌ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‹ค๋ฌด์—์„  ๋ถ€์ ํ•ฉํ•˜๋‹ค.

     - ์ค‘๊ฐ„ ํ…Œ์ด๋ธ”์ด ์ˆจ๊ฒจ์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

     - ์‚ฌ์šฉํ•˜์ง€ ๋ง์ž !!

 

4.1. ๋‹ค๋Œ€๋‹ค ๊ด€๊ณ„์˜ ๋Œ€์•ˆ 

     - ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”์„ ์—”ํ‹ฐํ‹ฐ๋กœ ์Šน๊ฒฉํ•˜๊ณ  ๋‹ค๋Œ€๋‹ค๋ฅผ ๋‹ค๋Œ€์ผ,์ผ๋Œ€๋‹ค๋กœ ๋ฐ”๊ฟ”์„œ ๋ณ€๊ฒฝํ•œ๋‹ค.

     - ์ด๋ ‡๊ฒŒํ•˜๋ฉด ์—ฐ๊ฒฐํ…Œ์ด๋ธ”์— ์—ฌ๋Ÿฌ ์ •๋ณด๋“ค์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.

 

+ Recent posts