• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    해결됨

주문 목록 검색 시, 랜더링 과정에서 LAZY 로딩 발생에 대한 질문

21.01.13 21:07 작성 조회수 157

4

안녕하세요. 김영한 강사님! 기본편부터 이번 챕터까지 덕분에 잘 배우고 있습니다!

제가 배웠던 내용을 되짚어 보면 프록시 객체가 초기화 되는 시점이 영속성 컨텍스트가 관리하는 중에  해당 프록시의 id를 제외한 다른 속성들을 호출하면 되는 것으로 이해하고 있는데요. 아니면 초기화 메소드를 사용하던가.

여기서 의문이 orderService를 통해 조회해서 받아온 List<Order> orders는 프록시 객체를 담은채로 반환이 되는 걸로 추측이 되는데. model.addAttribute()로 orders를 담은 후 "orders/orderList" 페이지를 렌더링 하는 과정 중에

<table class="table table-striped">
	<thead>
		<tr>
			<th>#</th>
			<th>회원명</th>
			<th>대표상품 이름</th>
			<th>대표상품 주문가격</th>
			<th>대표상품 주문수량</th>
			<th>상태</th>
			<th>일시</th>
			<th></th>
		</tr>
	</thead>
	<tbody>
		<tr th:each="item : ${orders}">
			<td th:text="${item.id}"></td>
			<td th:text="${item.member.username}"></td>
			<td th:text="${item.orderItems[0].item.name}"></td>
			<td th:text="${item.orderItems[0].orderPrice}"></td>
			<td th:text="${item.orderItems[0].count}"></td>
			<td th:text="${item.status}"></td>
			<td th:text="${item.orderDate}"></td>
			<td><a th:if="${item.status.name() == 'ORDER'}" href="#"
				th:href="'javascript:cancel('+${item.id}+')'"
				class="btn btn-danger">CANCEL</a></td>
		</tr>
	</tbody>
</table>

item.member.username에서 member를 lazy 로딩하고 item.orderItems[0].item.name에서 orderItem과 item을 lazy 로딩을 하는 것을 확인할 수 있었습니다.

저는 이번 과정을 통해서 @Transactional 어노테이션이 붙은 Service 로직 내에서만 영속성 컨텍스트가 엔티티를 관리해준다고 나름대로 이해를 했었는데, Service 영역을 벗어난 곳에서도 영속성 컨텍스트가 지연 로딩을 하는 것을 보니 조금 당혹스럽더라구요!

그래서 핵심 질문은 프록시 객체들이 @Transactional이 붙은 Service 로직 내를 벗어났는데 왜 lazy 로딩이 신기하게도 잘 발생하는지?가 궁금합니다 ㅎㅎ! 

추가) 같은 member, 같은 item을 가진 order를 2개 조회해봤는데요! 1차 캐시에 의해 lazy 로딩이 첫번째 table 목록을 구성하는데만 발생하고 두번째 목록을 구성할 때는 member와 item 엔티티를 받는데에 select 쿼리를 새로 DB에 안 날리고 영속성 컨텍스트의 1차 캐시에 등록된 엔티티를 반환 받는 것도 확인이 되네요.

답변 2

·

답변을 작성해보세요.

4

안녕하세요. 구태균님^^ 공부를 제대로 하셨군요^^!

여기서 딱! 의문을 가지면, 지금까지 공부를 잘 해오신 것이 맞습니다.

이제 OSIV라는 마지막 퍼즐 조각이 하나 남아있습니다.

스프링과 JPA를 그냥 사용할 때는 당연히 지연로딩 문제가 발생해야 하는데, 스프링 부트는 OSIV라는 특별한 기능을 기본으로 추가해줍니다.

쉽게 이야기해서 HTTP 요청이 나갈 때 까지 영속성 컨텍스트를 강제로 유지시켜주는 방법입니다.(보통은 트랜잭션이 종료되면 같이 종료하지만, OSIV를 사용하면 트랜잭션이 종료되어도 HTTP 요청이 끝날 때 까지 유지됩니다.)

참고로 활용2편에서 OSIV에 대해서 자세히 설명드립니다^^

감사합니다.

3

구태균님의 프로필

구태균

질문자

2021.01.14

감사합니다 ㅎㅎ! 덕분에 활용2편까지 더 힘차게 들을 수 있겠네요!