inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

주문 목록 검색, 취소

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

해결된 질문

271

구태균

작성한 질문수 1

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차 캐시에 등록된 엔티티를 반환 받는 것도 확인이 되네요.

JPA spring spring-boot java 웹앱

답변 2

4

김영한

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

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

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

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

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

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

감사합니다.

3

구태균

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

OrderServiceTest 상문주문 테스트 시 update 쿼리 문의

0

27

1

sdk 설정 오류

0

65

2

오탈자 - @Transactional

0

62

1

src/test/resources 테스트 경로 문제

0

56

1

상품 등록후 H2 db 출력 순서 바꿀 수 있나요?

0

70

1

MemberRepositoryTest 실행오류

0

89

1

boot 4.x >>> trasasction rolled back log & p6spy(영한님, 수업 자료 업데이트 해주시면 감사하겠습니다!!)

1

195

2

강의 마지막 QueryDSL 사용 부분 질문있습니다

1

153

2

클라이언트에서 isbn과 author 수정 요청을 한 경우에 대해 질문드립니다.

0

56

1

도메인 모델 패턴 vs 트랜잭션 스크립트 패턴

0

80

1

기본 생성자

0

66

1

h2 DB 연결시 jdbc url 변경 이유가 궁금합니다.

0

106

1

멤버서비스테스트 부분에서 막힙니다.

0

173

4

실무에서도 EntityManager를 이용해서 많이 작업하는 편일까요?

0

124

1

초반에 h2 다운로드 과정 꼭 필요한가요?

0

128

2

자신 필드에도 get으로 접근하는 이유가 있을까요?

0

121

1

24분 27초 연관관계 편의 메서드 위치

0

118

1

단건 주문만 가능하게 한건 의도한 부분이신가요?

0

114

2

빌드 툴, Gradle

0

63

1

h2연결은 된 것 같은데 엔티티 테이블까지 작성 후 확인해보아도 테이블이 안보입니다

0

81

2

Repository에서 EntityManager 주입 방식 차이

0

97

1

롬복과 사용자 정의 setter 메서드

0

77

1

주문 목록 조회 fetch join 질문드립니다

0

91

1

dirty checking 질문드립니다.

0

86

1