월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
OSIV에 대해 질문이 있습니다.
질문1커넥션을 많이 사용하지 않는 경우 OSIV를 키고,실시간 요청이 많은 경우는 OSIV를 끈다고 했는데OSIV를 끄는 경우가 스트리밍 서비스나, 채팅 기능에 해당할가요 ?? 질문2질문1의 내용이 맞다면 만약 프로젝트에 게시판, 작성자와 1:1 채팅 기능이 있다면,게시판은 OSIV를 키고, 채팅 기능을 담고 있는 로직들에만 별도로 OSIV를 끄는 옵션이 따로 있나요??아니면 제가 멀티 모듈을 사용한적이 없어 자세히는 모르지만 멀티 모듈을 사용해서 각 기능들을 모듈화해서 따로 옵션을 설정하는건가요??
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
컬렉션 조회 최적화 - 엔티티 조회 vs DTO 직접 조회
안녕하세요 강의 정말 잘 듣고있습니다.해당 챕터의 마지막 강의인 "API 개발 고급 정리" 영상에서 엔티티 조회 방식과 DTO 직접 조회 방식 중 어떤 것을 더 권장하는지에 대해 설명해주시는 부분에 대해 질문이 생겼습니다.저는 아무래도 DTO 조회 방식은 쿼리문도 까다롭고 DTO를 추가로 만들어야 하기 때문에 우선 손이 잘 안가는 느낌이있었던 반면에,엔티티 조회는 쿼리가 더 단순하고 배치사이즈 옵션으로 쉽게 페이징도 적용할 수 있어서 좀 더 다가오긴했습니다.두 방식에 대한 차이와 장단점을 듣고나서는 네트워크 성능과 컴퓨터 성능이 워낙 좋아져서 엔티티 조회 방식으로 접근해도 거의 충분하다라고 이해를 했는데요.강의를 만드신 시기가 몇년 전인만큼 현재는 시간이 흘러 네트워크 성능과 컴퓨터 성능이 더 발전했는데지금은 엔티티 조회하는 방식만으로 컬렉션 조회하는데 성능 문제가 없을까요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
DTO에 관해서 질문드립니다!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]DTO를 만들때강의에서는 하나의 클래스에서 inner 클래스로 DTO를 만드셨는데 실제 실무에서도 이러한 방식으로 하는지 궁금합니다. 그리고 컨트롤러에서 람다와 스트림을 통해서 데이터 정제 하는 로직은 컨트롤러에서 처리해도 상관이 없는지 궁금합니다.
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
19:04 초 where in 쿼리 대신 where array_conatins 쿼리가 나왔습니다. (스프링 부트 3.1)
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]현재 스프링 부트 3.1 로 강의를 따라가고 있습니다.default_batch_fetch_size:10 을 설정해서 나가는 쿼리가 줄어드는 것을 확인했습니다만, 쿼리가 두 개가 아니고 총 세 개가 나왔습니다.023-06-13T23:24:02.666+09:00 DEBUG 68750 --- [nio-8080-exec-5] org.hibernate.SQL : select o1_0.order_id, d1_0.delivery_id, d1_0.city, d1_0.street, d1_0.zipcode, d1_0.status, m1_0.memeber_id, m1_0.city, m1_0.street, m1_0.zipcode, m1_0.name, o1_0.order_date, o1_0.status from orders o1_0 join member m1_0 on m1_0.memeber_id=o1_0.member_id join delivery d1_0 on d1_0.delivery_id=o1_0.delivery_id offset ? rows fetch first ? rows only 2023-06-13T23:24:02.676+09:00 INFO 68750 --- [nio-8080-exec-5] p6spy : #1686666242676 | took 2ms | statement | connection 8| url jdbc:h2:tcp://localhost/~/springbootjpa select o1_0.order_id,d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status,m1_0.memeber_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.name,o1_0.order_date,o1_0.status from orders o1_0 join member m1_0 on m1_0.memeber_id=o1_0.member_id join delivery d1_0 on d1_0.delivery_id=o1_0.delivery_id offset ? rows fetch first ? rows only select o1_0.order_id,d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status,m1_0.memeber_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.name,o1_0.order_date,o1_0.status from orders o1_0 join member m1_0 on m1_0.memeber_id=o1_0.member_id join delivery d1_0 on d1_0.delivery_id=o1_0.delivery_id offset 0 rows fetch first 100 rows only; 2023-06-13T23:24:02.681+09:00 DEBUG 68750 --- [nio-8080-exec-5] org.hibernate.SQL : select o1_0.order_id, o1_0.order_item_id, o1_0.count, o1_0.item_id, o1_0.order_price from order_item o1_0 where array_contains(?,o1_0.order_id) 2023-06-13T23:24:02.689+09:00 INFO 68750 --- [nio-8080-exec-5] p6spy : #1686666242689 | took 0ms | statement | connection 8| url jdbc:h2:tcp://localhost/~/springbootjpa select o1_0.order_id,o1_0.order_item_id,o1_0.count,o1_0.item_id,o1_0.order_price from order_item o1_0 where array_contains(?,o1_0.order_id) select o1_0.order_id,o1_0.order_item_id,o1_0.count,o1_0.item_id,o1_0.order_price from order_item o1_0 where array_contains('ar2: ARRAY [CAST(1 AS BIGINT), CAST(2 AS BIGINT), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL]',o1_0.order_id); 2023-06-13T23:24:02.690+09:00 DEBUG 68750 --- [nio-8080-exec-5] org.hibernate.SQL : select i1_0.item_id, i1_0.dtype, i1_0.category_item_id, i1_0.name, i1_0.price, i1_0.stock_quantity, i1_0.author, i1_0.isbn, i1_0.artist, i1_0.etc from item i1_0 where array_contains(?,i1_0.item_id) 2023-06-13T23:24:02.691+09:00 INFO 68750 --- [nio-8080-exec-5] p6spy : #1686666242691 | took 0ms | statement | connection 8| url jdbc:h2:tcp://localhost/~/springbootjpa select i1_0.item_id,i1_0.dtype,i1_0.category_item_id,i1_0.name,i1_0.price,i1_0.stock_quantity,i1_0.author,i1_0.isbn,i1_0.artist,i1_0.etc from item i1_0 where array_contains(?,i1_0.item_id) select i1_0.item_id,i1_0.dtype,i1_0.category_item_id,i1_0.name,i1_0.price,i1_0.stock_quantity,i1_0.author,i1_0.isbn,i1_0.artist,i1_0.etc from item i1_0 where array_contains('ar3: ARRAY [CAST(1 AS BIGINT), CAST(2 AS BIGINT), CAST(3 AS BIGINT), CAST(4 AS BIGINT), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL]',i1_0.item_id); 수강 중에 제가 따라 작성한 코드를 스프링부트 2.4.1에 그대로 옮겨보니 강의 내용대로 where in 쿼리가 나오는 것을 확인했습니다.스프링부트 버전 차이에서 나오는 쿼리가 달라진 것 같은데, 제 생각이 맞을까요? 답변 확인 : 빠르게 답변해주셔서 감사합니다!!덕분에 array_contains 로 최적화된 이유를 쉽게 이해할 수 있었습니다. (Hibernate에서 최적화를 했었었군요!)아 그리고 강의 내용에서 쿼리 세 개 나온다는 것을 확인했습니다(잘못 본 것에 대해 질문글에서 수정을 해놨어야 했는데 빼놓지 않았었네요 ㅠㅠ)다시 한번 상세한 답변 정말 감사드립니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
V1: 엔티티 직접노출 질문입니다.
@JsonIgnore는 양방향 관계의 무한루프를 막기 위해 설정하는 것이고, @GetMapping("/api/v1/orders") public List<Order> ordersV1() { List<Order> all = orderRepository.findAllByString(new OrderSearch()); for (Order order : all) { order.getMember().getName(); order.getDelivery().getAddress(); List<OrderItem> orderItems = order.getOrderItems(); orderItems.forEach(o -> o.getItem().getName()); } return all; }위에 처럼 프록시 초기화(하지만 실제 엔티티의 참조만 가질뿐 객체는 여전히 프록시)를 해주는 이유는 실제 엔티티의 참조를 가지게 하려고 설정하는 것이고,@Bean Hibernate5Module hibernate5Module() { return new Hibernate5Module(); }위에 처럼 Hibernate5Module을 해주는 이유는 프록시 초기화를 해도 객체는 여전히 프록시기 때문에 Json으로 반환할 수 있게 하려는 것이라고 이해했습니다.여기 까지 이해한 부분이 옳게 이해한 것일까요?그리고 마지막으로 @Bean Hibernate5Module hibernate5Module() { Hibernate5Module hibernate5Module = new Hibernate5Module(); // 강제 지연 로딩 설정 hibernate5Module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, true); return new Hibernate5Module(); }위에 처럼 강제 지연 로딩 설정을 왜 쓰는지는 잘 모르겠습니다.강제 지연 로딩 설정이라는 말이 무엇인가요!?혹시 하이버네이트가 @ToOne은 기본이 eager인데 엔티티에서 직접 lazy 설정해준걸 안해도 된다는 소리인가요? 질문이 크게 숫자로 표시한 두가지 입니다! 감사합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
1+n 문제 관련 궁금증 입니다.
1+n문제에서 n이 1에서 조회한 갯수 라고 하셨는데요.order 2개를 찾았을 때 member와 delivery를 불러와야 하므로 1 + 2*2 인 것 같습니다.만약 멤버와 딜리버리 말고 찾아야하는 지연 로딩 속성이 10개 라면 1+2*10 이니까 사실은 1+N이 자세히 보면 1+N*M 문제 라고 혼자 나름대로 이해를 해도 괜찮을까요?M은 상수라서 생략하는 거 같은데 혹시 맞을까요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
default_batch_fetch_size 설정을 지워도 지연로딩이 적용되지 않습니다.
default_batch_fetch_size 설정을 주었을때 쿼리가 나가는것과 default_batch_fetch_size 설정을 주석처리 했을때 쿼리 나가는것을 비교해보고 싶어서 테스트 코드를 아래와 같이 작성해봤습니다.@Test @DisplayName("회원 불러와서 getFriends 할때, default_batch_fetch_size 설정 여부에 따른 쿼리 개수 확인") public void findOne() throws Exception { //given Member member = Member.builder() .name("userA") .build(); Friend friendA = Friend.builder() .name("friendA") .member(member) .build(); Friend friendB = Friend.builder() .name("friendB") .member(member) .build(); Friend friendC = Friend.builder() .name("friendC") .member(member) .build(); Friend friendD = Friend.builder() .name("friendD") .member(member) .build(); Friend friendE = Friend.builder() .name("friendE") .member(member) .build(); //when memberRepository.save(member); friendRepository.save(friendA); friendRepository.save(friendB); friendRepository.save(friendC); friendRepository.save(friendD); friendRepository.save(friendE); em.flush(); em.clear(); //then Member findMember = memberRepository.findById(member.getId()); List<Friend> friends = findMember.getFriends(); for (Friend friend : friends) { log.info("getClass: " + friend.getClass()); // 프록시객체를 기대.. log.info("getClass: " + friend.getName()); } }Member와 Friend는 일대다 관계이며,Member 클래스에 있는 연관관계 필드는 다음과 같고,@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) private final List<Friend> friends = new ArrayList<>();Friend 클래스에 있는 연관관계 필드는 다음과 같습니다.@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="member_id") private Member member;테스트코드에서,,Member findMember = memberRepository.findById(member.getId()); 이 부분에서 member를 조회하는 쿼리가 한번,log.info("getClass: " + friend.getClass()); 이 부분에서 프록시객체가 찍히고,log.info("getClass: " + friend.getName()); 이 부분에서 원본 객체를 조회하기 위해 쿼리가 한번 나가서, for문을 돌면서 총 1 + 5 개의 쿼리가 나가기를 기대했습니다.그리고 default_batch_fetch_size:100 를 글로벌설정에 주게 되면 멤버 조회하는 쿼리 1번, 해당 멤버와 관련된 전체 friend 들을 다 조회하는 쿼리 1번이 나가고 더이상 안나가게 되지 않을까 기대했습니다.그런데, 글로벌설정을 주기도 전에 1+5개의 조회 쿼리가 나가지가 않고 2개의 조회쿼리만 나가고 끝이 나네요..default_batch_fetch_size:100 이 옵션을 주석처리도 해보고, 아예 지워도 보고 default_batch_fetch_size:1 로도 값을 변경해보기도 하였지만 결과는 같았습니다.로그는 다음과 같습니다.2023-06-09 21:35:26.695 INFO 1106 --- [ Test worker] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@1bdaa23d testClass = MemberRepositoryTest, testInstance = com.example.myvers.member.MemberRepositoryTest@7ae75ba6, testMethod = findOne@MemberRepositoryTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@79f227a9 testClass = MemberRepositoryTest, locations = '{}', classes = '{class com.example.myvers.MyversApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@42f48531, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@ea9b7c6, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@a8e6492, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@60dce7ea, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@f73dcd6, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@43015c69], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@7b6b466a]; rollback [true] 2023-06-09 21:35:26.749 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : call next value for hibernate_sequence 2023-06-09 21:35:26.749 INFO 1106 --- [ Test worker] p6spy : #1686314126749 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b call next value for hibernate_sequence call next value for hibernate_sequence; 2023-06-09 21:35:26.750 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : call next value for hibernate_sequence 2023-06-09 21:35:26.750 INFO 1106 --- [ Test worker] p6spy : #1686314126750 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b call next value for hibernate_sequence call next value for hibernate_sequence; 2023-06-09 21:35:26.750 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : call next value for hibernate_sequence 2023-06-09 21:35:26.750 INFO 1106 --- [ Test worker] p6spy : #1686314126750 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b call next value for hibernate_sequence call next value for hibernate_sequence; 2023-06-09 21:35:26.750 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : call next value for hibernate_sequence 2023-06-09 21:35:26.750 INFO 1106 --- [ Test worker] p6spy : #1686314126750 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b call next value for hibernate_sequence call next value for hibernate_sequence; 2023-06-09 21:35:26.750 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : call next value for hibernate_sequence 2023-06-09 21:35:26.750 INFO 1106 --- [ Test worker] p6spy : #1686314126750 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b call next value for hibernate_sequence call next value for hibernate_sequence; 2023-06-09 21:35:26.750 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : call next value for hibernate_sequence 2023-06-09 21:35:26.750 INFO 1106 --- [ Test worker] p6spy : #1686314126750 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b call next value for hibernate_sequence call next value for hibernate_sequence; 2023-06-09 21:35:26.751 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : insert into member (created_date, email, grade, login_id, name, password, talk_count, member_id) values (?, ?, ?, ?, ?, ?, ?, ?) 2023-06-09 21:35:26.752 INFO 1106 --- [ Test worker] p6spy : #1686314126752 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b insert into member (created_date, email, grade, login_id, name, password, talk_count, member_id) values (?, ?, ?, ?, ?, ?, ?, ?) insert into member (created_date, email, grade, login_id, name, password, talk_count, member_id) values (NULL, NULL, NULL, NULL, 'userA', NULL, 1, 33); 2023-06-09 21:35:26.752 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (?, ?, ?, ?, ?, ?, ?, ?) 2023-06-09 21:35:26.752 INFO 1106 --- [ Test worker] p6spy : #1686314126752 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (?, ?, ?, ?, ?, ?, ?, ?) insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (0, NULL, NULL, NULL, NULL, 33, 'friendA', 34); 2023-06-09 21:35:26.752 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (?, ?, ?, ?, ?, ?, ?, ?) 2023-06-09 21:35:26.752 INFO 1106 --- [ Test worker] p6spy : #1686314126752 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (?, ?, ?, ?, ?, ?, ?, ?) insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (0, NULL, NULL, NULL, NULL, 33, 'friendB', 35); 2023-06-09 21:35:26.753 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (?, ?, ?, ?, ?, ?, ?, ?) 2023-06-09 21:35:26.753 INFO 1106 --- [ Test worker] p6spy : #1686314126753 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (?, ?, ?, ?, ?, ?, ?, ?) insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (0, NULL, NULL, NULL, NULL, 33, 'friendC', 36); 2023-06-09 21:35:26.753 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (?, ?, ?, ?, ?, ?, ?, ?) 2023-06-09 21:35:26.753 INFO 1106 --- [ Test worker] p6spy : #1686314126753 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (?, ?, ?, ?, ?, ?, ?, ?) insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (0, NULL, NULL, NULL, NULL, 33, 'friendD', 37); 2023-06-09 21:35:26.753 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (?, ?, ?, ?, ?, ?, ?, ?) 2023-06-09 21:35:26.753 INFO 1106 --- [ Test worker] p6spy : #1686314126753 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (?, ?, ?, ?, ?, ?, ?, ?) insert into friend (age, created_date, gender, image_name, mbti, member_id, name, friend_id) values (0, NULL, NULL, NULL, NULL, 33, 'friendE', 38); 2023-06-09 21:35:26.759 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : select member0_.member_id as member_i1_1_0_, member0_.created_date as created_2_1_0_, member0_.email as email3_1_0_, member0_.grade as grade4_1_0_, member0_.login_id as login_id5_1_0_, member0_.name as name6_1_0_, member0_.password as password7_1_0_, member0_.talk_count as talk_cou8_1_0_ from member member0_ where member0_.member_id=? 2023-06-09 21:35:26.760 INFO 1106 --- [ Test worker] p6spy : #1686314126760 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b select member0_.member_id as member_i1_1_0_, member0_.created_date as created_2_1_0_, member0_.email as email3_1_0_, member0_.grade as grade4_1_0_, member0_.login_id as login_id5_1_0_, member0_.name as name6_1_0_, member0_.password as password7_1_0_, member0_.talk_count as talk_cou8_1_0_ from member member0_ where member0_.member_id=? select member0_.member_id as member_i1_1_0_, member0_.created_date as created_2_1_0_, member0_.email as email3_1_0_, member0_.grade as grade4_1_0_, member0_.login_id as login_id5_1_0_, member0_.name as name6_1_0_, member0_.password as password7_1_0_, member0_.talk_count as talk_cou8_1_0_ from member member0_ where member0_.member_id=33; 2023-06-09 21:35:26.765 DEBUG 1106 --- [ Test worker] org.hibernate.SQL : select friends0_.member_id as member_i8_0_0_, friends0_.friend_id as friend_i1_0_0_, friends0_.friend_id as friend_i1_0_1_, friends0_.age as age2_0_1_, friends0_.created_date as created_3_0_1_, friends0_.gender as gender4_0_1_, friends0_.image_name as image_na5_0_1_, friends0_.mbti as mbti6_0_1_, friends0_.member_id as member_i8_0_1_, friends0_.name as name7_0_1_ from friend friends0_ where friends0_.member_id=? 2023-06-09 21:35:26.766 INFO 1106 --- [ Test worker] p6spy : #1686314126766 | took 0ms | statement | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b select friends0_.member_id as member_i8_0_0_, friends0_.friend_id as friend_i1_0_0_, friends0_.friend_id as friend_i1_0_1_, friends0_.age as age2_0_1_, friends0_.created_date as created_3_0_1_, friends0_.gender as gender4_0_1_, friends0_.image_name as image_na5_0_1_, friends0_.mbti as mbti6_0_1_, friends0_.member_id as member_i8_0_1_, friends0_.name as name7_0_1_ from friend friends0_ where friends0_.member_id=? select friends0_.member_id as member_i8_0_0_, friends0_.friend_id as friend_i1_0_0_, friends0_.friend_id as friend_i1_0_1_, friends0_.age as age2_0_1_, friends0_.created_date as created_3_0_1_, friends0_.gender as gender4_0_1_, friends0_.image_name as image_na5_0_1_, friends0_.mbti as mbti6_0_1_, friends0_.member_id as member_i8_0_1_, friends0_.name as name7_0_1_ from friend friends0_ where friends0_.member_id=33; 2023-06-09 21:35:26.768 INFO 1106 --- [ Test worker] c.e.myvers.member.MemberRepositoryTest : getClass: class com.example.myvers.domain.Friend 2023-06-09 21:35:26.768 INFO 1106 --- [ Test worker] c.e.myvers.member.MemberRepositoryTest : getClass: friendA 2023-06-09 21:35:26.768 INFO 1106 --- [ Test worker] c.e.myvers.member.MemberRepositoryTest : getClass: class com.example.myvers.domain.Friend 2023-06-09 21:35:26.768 INFO 1106 --- [ Test worker] c.e.myvers.member.MemberRepositoryTest : getClass: friendB 2023-06-09 21:35:26.768 INFO 1106 --- [ Test worker] c.e.myvers.member.MemberRepositoryTest : getClass: class com.example.myvers.domain.Friend 2023-06-09 21:35:26.768 INFO 1106 --- [ Test worker] c.e.myvers.member.MemberRepositoryTest : getClass: friendC 2023-06-09 21:35:26.768 INFO 1106 --- [ Test worker] c.e.myvers.member.MemberRepositoryTest : getClass: class com.example.myvers.domain.Friend 2023-06-09 21:35:26.768 INFO 1106 --- [ Test worker] c.e.myvers.member.MemberRepositoryTest : getClass: friendD 2023-06-09 21:35:26.768 INFO 1106 --- [ Test worker] c.e.myvers.member.MemberRepositoryTest : getClass: class com.example.myvers.domain.Friend 2023-06-09 21:35:26.768 INFO 1106 --- [ Test worker] c.e.myvers.member.MemberRepositoryTest : getClass: friendE 2023-06-09 21:35:26.771 INFO 1106 --- [ Test worker] p6spy : #1686314126771 | took 0ms | rollback | connection 16| url jdbc:h2:mem:bd08892f-1de8-4235-819c-08b14b2b1f5b ; 2023-06-09 21:35:26.772 INFO 1106 --- [ Test worker] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@1bdaa23d testClass = MemberRepositoryTest, testInstance = com.example.myvers.member.MemberRepositoryTest@7ae75ba6, testMethod = findOne@MemberRepositoryTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@79f227a9 testClass = MemberRepositoryTest, locations = '{}', classes = '{class com.example.myvers.MyversApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@42f48531, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@ea9b7c6, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@a8e6492, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@60dce7ea, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@f73dcd6, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@43015c69], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]] 결론: default_batch_fetch_size 설정을 지워도 지연로딩이 적용되지 않는 이유를 알고싶습니다. 감사합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
JpaRepository 여러 entity에서 사용 시
JpaRepository 여러 entity에서 사용 시에 각각 마다 레포 생성해야 되나여?아래와 같은 경우요public interface BoardFileRepository extends JpaRepository<BoardFile,Long> {}public interface BoardRepository extends JpaRepository<Board,Long>, BoardRepositoryCustom { @QueryHints({ @QueryHint(name = org.hibernate.annotations.QueryHints.COMMENT, value = "BoardRepository.findByName") }) Board findByName(String name);}
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
실무에서는 그럼 spring.jpa.open-in-view: false 로 설정하는 경우가 많은가요 ?
실무에서spring.jpa.open-in-view: false로 설정하는 경우가 많은가요 ? 또한 사이드 프로젝트 정도로 규모가 작을 경우그냥 기본 설정대로 true로 사용해도 되나요 ?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
배치처리를 하려면 어떻게 해야하나요?
스프링이 제공하는 기능이 아니라 제가 직접해줘야하는건가요? 영속성 컨텍스트가 일정이상 차면 비워주는 작업을 어떻게 할 수 있을까요?코드가 나와있긴하지만 그 코드는 너무 로우 레벨아닌가요?? SPRING DATA JPA사용하면서 em을 직접적으로 사용하진 않잖아요..자동으로 해주는건가요...?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
프록시 벗기기가 언제 필요하나요?
어떤 상황에서 하이버네이트가 제공하는 프록시벗기기가 필요한가요?(프록시 객체에서 원본객체를 가져오는 메서드가 필요한 상황)
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
osiv관련 질문
osiv가 뷰에서도 지연로딩이 가능하게 하려고 도입한거잖아요 (뷰에서 필요한값들을 지연로딩으로 가져오려고)근데 지연로딩을 하면 결국 필요없는 쿼리가 추가로 나가게될텐데..애초에 필요한 데이터만 jpql사용해서 뽑아서 주면 문제가 해결되는거아닌가요? 왜osiv를 사용하는거죠?? 뷰와 리파지토리가 너무 연관되어서 그런가요..? 그게 그렇게 큰 단점인가요..?뭔가 osiv의 장점이 엄청많아보이는데 제가 다른 분들 프로젝트를 봤을때는 osiv를 거의 적용안했던것같거든요... 왜 잘 안쓰이는걸까요...
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
osiv OFF했을 때 ordersV1 실행시 질문 있습니다.
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 네2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 네3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)네[질문 내용] @GetMapping("/api/v1/orders") public List<Order> ordersV1() { List<Order> all = orderRepository.findAllByString(new OrderSearch()); for (Order order : all) { order.getMember().getName(); order.getDelivery().getAddress(); List<OrderItem> orderItems = order.getOrderItems(); orderItems.stream().forEach(o -> o.getItem().getName()); } return all; }OSIV를 껏을 경우에 order.getMember().getName()에서 에러가 뜨는게 맞다고하셨습니다. 그런데 ordersv1 사용시에 findAllByString을 사용하면서 트랜잭션을 애초에 사용하지 않았는데 어느 타이밍에 트랜잭션이 켜지고 꺼지면서 커넥션이 사라지는지 궁금합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Result 클래스로 dto를 감싸는 이유
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요. Result 클래스로 dto를 감싸는 이유는 무엇인가요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Spring JPA Order by nullsHandling 지원 여부
데이터에 빈값과 null값이 있다고 할 때, order by column asc : 빈 값 우선 , null 값 맨 뒤order by column desc : null 값 우선, 빈 값 맨 뒤와 같이 정렬이 되는데빈 값과 null 값을 같은 위치에 정렬하고 싶어서 아래와 같이 코드를 짜서 구현을 했는데List<Order> orderList= new ArrayList<>(); //... 생략 if(StringUtils.equals(SORT_DESC, direction)) { orderList.add(new Order(Direction.fromString(direction), column).nullsLast()); } else { orderList.add(new Order(Direction.fromString(direction), column).nullsFirst()); } // ... Sort.by(orderList); Sort 객체에는 NULLS_LAST나 NULLS_FIRST 세팅이 잘 되는데jpa 쿼리로그에는 그냥 column에 대한 정렬밖에 없더라구요 좀 찾아보니, jpa 에서 nullHandling을 지원하지 않는다는 것도 같은데,https://github.com/spring-projects/spring-data-jpa/issues/1280이런 경우 대체할 수 있는 방법이 뭐가 있을까요? ㅠ
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
ordersV4에서 에러가 발생하는데 무슨 문제인지 잘 모르겠습니다. (아직 정확한 원인을 모르겠습니다. 알려주세요~~)
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]환경spring boot : 3.0.6java : 17코드https://github.com/pdh9311/jpashop 세번째 커밋에 에러가 발생합니다.org.hibernate.query.SemanticException: query specified join fetching, but the owner of the fetched association was not present in the select list [SqmSingularJoin(study.jpashop.domain.Order(o).member(m) : member)]이런 에러가 발생합니다.약간 클래스이름만 다르지 거의 강의 내용과 같게 한거 같은데 안되네요.. 예전에 할땐 된거 같은데. 무슨 문제일까요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
강의 5:00~
아직 기본기가 완벽하지 않아서 헷갈리는 부분이 있습니다. 선생님께서 order.getOrderItems()할때 엔티티니까 조회가 안된다. 라고 하셨습니다. 이해가 안되서 생각해봤는데 Entity OrderItem이 지연로딩에 해당되서 stream으로 값을 불려와야한다 라고 이해하면 될까요??public OrderDto(Order order) { orderId = order.getId(); name = order.getMember().getName(); orderDate = order.getOrderDate(); orderStatus = order.getStatus(); address = order.getDelivery().getAddress(); orderItems = order.getOrderItems().stream() .map(orderItem -> new OrderItemDto(orderItem)) .collect(toList()); }
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
분산 데이터베이스 환경에서도 cqs패턴을 사용할 수 있나요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]커맨드와 쿼리를 분리한다고 하셨는데,분산 데이터베이스 환경에서 update 쿼리에서 반환값을 가져오지 않고 다시 findOne을 수행한다고 가정했을때 전파가 아직 이루어지지 않아서 조회가 안되는 경우가 발생할 수도 있을까요?이전에 물리적으로 분산 데이터베이스 환경에서 update되는 데이터가 많아서 find로 값을 불러오지 못한 경우가 있어서무조건 update 쿼리를 보낼때 반환값을 받아서 처리했던 기억이 있어서 질문 드립니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
List로 만든 뒤 Map으로 변환시 메모리 사용
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.V5를 만들면서 List를 만든 뒤에 이것을 다시 Map으로 변환하셨는데 이럴 경우 메모리 사용량이 많아져 OOM이 발생하기 쉬울 수 있다고 생각했습니다. 제가 생각한게 맞을까요?만약 맞다면 em에서 받아올때부터 stream으로 받아서 map으로 만들면 이러한 문제가 해결될까요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
9:56 경 "JSON의 루트는 배열로 해서는 안된다." 에 대한 질문
안녕하세요! JSON과 배열에 대해 질문드립니다!9:56 경에, 영한님께서 "JSON의 루트는 배열로 해서는 안된다."라고 언급해주셨습니다. 이것은 혹시, 클라이언트 쪽에서 해당 배열에 접근할 수 있는 방법이 없어서이기 때문일까요..?확인해주셔서 감사드립니다!