월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
N + 1 쿼리 횟수
안녕하세요 강의 너무 잘 듣고 있습니다."간단한 주문 조회 V2: 엔티티를 DTO로 변환" 강의를 듣던 중 궁금한 점이 생겨 질문 드립니다.Order 엔티티를 SimpleOrderDto로 변환하는 과정에서 아래 조건으로 인해 샘플 데이터 2개 기준 총 5(1 + 2 + 2)번의 쿼리가 날아간다고 이해했습니다.order -> member 지연 로딩 조회 N번order -> delivery 지연 로딩 조회 N번근데 저는 order -> delivery 쿼리 이후에 order를 찾는 쿼리가 한번 더 날아가는 것처럼 보입니다. 총 7번의 쿼리가 발생하는 것 같은데 무엇 때문인지 설명해주실 수 있을까요?코드와 콘솔 로그는 아래 첨부했습니다. 감사합니다.// Order 엔티티 @Id @GeneratedValue @Column(name = "order_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private Member member; @OneToMany(mappedBy = "order", cascade = CascadeType.ALL) private List<OrderItem> orderItems = new ArrayList<>(); @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "delivery_id") private Delivery delivery; private LocalDateTime orderDate; @Enumerated(EnumType.STRING) private OrderStatus status; // 주문상태 // Delivery 엔티티 @Id @GeneratedValue @Column(name = "delivery_id") private Long id; @JsonIgnore @OneToOne(mappedBy = "delivery", fetch = FetchType.LAZY) private Order order; @Embedded private Address address; @Enumerated(EnumType.STRING) private DeliveryStatus status; // READY, COMP // OrderSimpleApiController @GetMapping("/api/v2/simple-orders") public List<SimpleOrderDTO> ordersV2() { List<Order> orders = orderRepository.findAll(new OrderSearch()); return orders.stream() .map(SimpleOrderDTO::new) .toList(); } @Data static class SimpleOrderDTO { private Long orderId; private String name; private LocalDateTime orderDate; private OrderStatus orderStatus; private Address address; public SimpleOrderDTO(Order order) { this.orderId = order.getId(); this.name = order.getMember().getName(); // Lazy 초기화 this.orderDate = order.getOrderDate(); this.orderStatus = order.getStatus(); this.address = order.getDelivery().getAddress(); // Lazy 초기화 } }2024-04-09T13:27:53.982+09:00 DEBUG 12424 --- [nio-8080-exec-2] org.hibernate.SQL : select o1_0.order_id, o1_0.delivery_id, o1_0.member_id, o1_0.order_date, o1_0.status from orders o1_0 join member m1_0 on m1_0.member_id=o1_0.member_id 2024-04-09T13:27:53.984+09:00 INFO 12424 --- [nio-8080-exec-2] p6spy : 1712636873984|0|statement|connection 7|url jdbc:h2:tcp://localhost/~/jpashop_v2|select o1_0.order_id,o1_0.delivery_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 join member m1_0 on m1_0.member_id=o1_0.member_id|select o1_0.order_id,o1_0.delivery_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 join member m1_0 on m1_0.member_id=o1_0.member_id 2024-04-09T13:27:54.005+09:00 DEBUG 12424 --- [nio-8080-exec-2] org.hibernate.SQL : select m1_0.member_id, m1_0.city, m1_0.street, m1_0.zipcode, m1_0.name from member m1_0 where m1_0.member_id=? 2024-04-09T13:27:54.007+09:00 INFO 12424 --- [nio-8080-exec-2] p6spy : 1712636874007|0|statement|connection 7|url jdbc:h2:tcp://localhost/~/jpashop_v2|select m1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.name from member m1_0 where m1_0.member_id=?|select m1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.name from member m1_0 where m1_0.member_id=1 2024-04-09T13:27:54.012+09:00 DEBUG 12424 --- [nio-8080-exec-2] org.hibernate.SQL : select d1_0.delivery_id, d1_0.city, d1_0.street, d1_0.zipcode, d1_0.status from delivery d1_0 where d1_0.delivery_id=? 2024-04-09T13:27:54.013+09:00 INFO 12424 --- [nio-8080-exec-2] p6spy : 1712636874013|0|statement|connection 7|url jdbc:h2:tcp://localhost/~/jpashop_v2|select d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status from delivery d1_0 where d1_0.delivery_id=?|select d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status from delivery d1_0 where d1_0.delivery_id=1 2024-04-09T13:27:54.016+09:00 DEBUG 12424 --- [nio-8080-exec-2] org.hibernate.SQL : select o1_0.order_id, o1_0.delivery_id, o1_0.member_id, o1_0.order_date, o1_0.status from orders o1_0 where o1_0.delivery_id=? 2024-04-09T13:27:54.016+09:00 INFO 12424 --- [nio-8080-exec-2] p6spy : 1712636874016|0|statement|connection 7|url jdbc:h2:tcp://localhost/~/jpashop_v2|select o1_0.order_id,o1_0.delivery_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 where o1_0.delivery_id=?|select o1_0.order_id,o1_0.delivery_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 where o1_0.delivery_id=1 2024-04-09T13:27:54.018+09:00 DEBUG 12424 --- [nio-8080-exec-2] org.hibernate.SQL : select m1_0.member_id, m1_0.city, m1_0.street, m1_0.zipcode, m1_0.name from member m1_0 where m1_0.member_id=? 2024-04-09T13:27:54.019+09:00 INFO 12424 --- [nio-8080-exec-2] p6spy : 1712636874019|0|statement|connection 7|url jdbc:h2:tcp://localhost/~/jpashop_v2|select m1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.name from member m1_0 where m1_0.member_id=?|select m1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.name from member m1_0 where m1_0.member_id=2 2024-04-09T13:27:54.020+09:00 DEBUG 12424 --- [nio-8080-exec-2] org.hibernate.SQL : select d1_0.delivery_id, d1_0.city, d1_0.street, d1_0.zipcode, d1_0.status from delivery d1_0 where d1_0.delivery_id=? 2024-04-09T13:27:54.020+09:00 INFO 12424 --- [nio-8080-exec-2] p6spy : 1712636874020|0|statement|connection 7|url jdbc:h2:tcp://localhost/~/jpashop_v2|select d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status from delivery d1_0 where d1_0.delivery_id=?|select d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status from delivery d1_0 where d1_0.delivery_id=2 2024-04-09T13:27:54.021+09:00 DEBUG 12424 --- [nio-8080-exec-2] org.hibernate.SQL : select o1_0.order_id, o1_0.delivery_id, o1_0.member_id, o1_0.order_date, o1_0.status from orders o1_0 where o1_0.delivery_id=? 2024-04-09T13:27:54.021+09:00 INFO 12424 --- [nio-8080-exec-2] p6spy : 1712636874021|0|statement|connection 7|url jdbc:h2:tcp://localhost/~/jpashop_v2|select o1_0.order_id,o1_0.delivery_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 where o1_0.delivery_id=?|select o1_0.order_id,o1_0.delivery_id,o1_0.member_id,o1_0.order_date,o1_0.status from orders o1_0 where o1_0.delivery_id=2
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
DTO 와 Entity 상호 변환 메소드 위치
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]DTO 관련하여 몇 가지 질문이 있습니다.API 별로 DTO 를 만들어서 관리를 하는 것도 이해했습니다. 근데 궁금한 점은 실무에서는 DTO <-> Entity 변환을 DTO 에 추가하나요 아니면 서비스 계층에서 DTO를 조작할 때 처리하나요 ? 예를 들면, 해당 변환을 각 DTO 에 맞게끔 넣어야하니까 toEntity, fromEntity 와 같은 메소드를 추가하는 것을 생각했습니다.(공통된 부분은 DTO base 클래스를 만들구요.)
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
문득 ArrayList 에 대해 궁금해졌습니다.
[질문 내용]안녕하세요! ArrayList 에 대해 이것저것 찾아보던 중 이런 내용이 있었습니다. ArrayList,Map 은 동시성 이슈가 있어 ArrayList 대신 CopyOnWriteArrayList를 Map 대신 ConCurrentHashMap 을 쓰라는 내용이었습니다. 이에 대해 실제 스프링으로 개발할 때 위 내용이 어떻게 응용되는지 이해가 안되고 찾지 못해서 질문드립니다. 뭐 단순히 ArrayList 에 정수 넣고 실험해서 동시성 이슈가 있다라고 파악을 한다고 치더라도 뭐 어느 경우에 적용해야 하는지 이해가 안갑니다. 질문 요약 1) ArrayList 대신 CopyOnWriteArrayList 를 써야 하는 실무적인 실제 예를 들어주세요! 지금까지 영한님한테 배웠던 대로 양방향 관계에서 List = new ArrayList<>로 초기화 해줬는데 그러면 이는 유저가 많은 멀티스레드 환경에서 위험한 것 아닌가요?? public PostResponseDto showDetailsPost(final Long postId){ //Post + PostImage + Post 게시글 작성자 함께 영속화 Post post = findPostWithFetchMemberAndImage(postId); //첫 댓글 Reply (대댓글 X) + 부모댓글 작성자 함께 영속화 List<Reply> parentReply = replyRepository.findParentReplyByPostIdWithFetchMember(postId); List<ReplyResponseDto> replyResponseDtoList = new ArrayList<>(); //부모-> 자식 순으로 DTO 순서 저장. for(Reply parent: parentReply){ replyResponseDtoList.add(ReplyResponseDto.of(parent,makeNickNameForReply(parent),makeContentsForReply(parent)));위 코드는 List<ReplyResponseDto> 를 new ArrayList<>() 로 초기화 해서 add 로 넣어주는 부분이 있습니다. 이런 부분도 다 CopyOnWriteArrayList를 써야 하는 것인가요? 2) Map 도 마찬가지입니다. 실제 Map 대신 ConcurrentHashMap 을 써야 했던 실무적인 예를 들어주시면 감사하겠습니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
dbInit2 메소드 질문
====[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요.dbInit2메서드를 똑같이 작성하고 db를 조회해봤는데 dbinit1 메서드에서 정의한 것만 db에 들어가고 dbinit2메서드 값은 db에 저장이 안됩니다혹시나 @Bean 등록후 확인해보니 등록이 되는데강의내용중 강사님은 @Bean등록 없이 그냥 하신것 같은데왜 이런걸까요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
orphanRemoval에서 발생하는 쿼리 관련하여 질문드립니다.
안녕하세요.OneToMany 관계에서 orphanRemoval = true 옵션으로 데이터 제거 관련하여 질문드립니다. MemberService.removeAddress() 로직에서 address를 제거하면 select address -> select member -> select address -> delete 순으로 쿼리가 발생합니다. select address 쿼리가 2번 발생하는데, 일반적으로 쿼리 2번을 발생시키면서 고아 객체 제거를 진행하는 걸까요? 아니면 다른 방식의 remove 과정이나 또는 select address 쿼리를 1번으로 줄일 수 있는 방법이 있다면 알려주실 수 있을까요? 감사합니다. @RequiredArgsConstructor @Slf4j @Service public class MemberService { private final AddressRepository addressRepository; @Transaction public void removeAddress(Long addressId) { Address address = addressRepository.findById(addressId) .orElseThrow(() -> new Exception()); Member member = address.getMember(); member.getAddresses().remove(address); } } @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "member_id") private Long id; @OneToMany(mappedBy = "member", cascade = CascadeType.PERSIST, orphanRemoval = true) private final List<Address> addresses = new ArrayList<>(); // .. 중략 } @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity public class Address { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "address_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private Member member; // .. 중략 }
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
fetch_size 크기만큼 null을 다 채워서 보내는데 이유를 모르겠습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]여기에 질문 내용을 남겨주세요. default_batch_fetch_size: 100 옵션을 주었을 때in 절에 2개의 값만 넣어도 되는 경우에도 size의 크기를 굳이 맞춰서 보내는 문제가 있습니다.예를들어 2개의 id 값만 보내도 된다면 아래와 같이 (1,2,null...) 으로 꼭 100개를 모두 맞춰서 보내게 됩니다.select oi1_0.order_id,oi1_0.order_item_id,oi1_0.count,oi1_0.item_id,oi1_0.order_price from order_item oi1_0 where oi1_0.order_id in (1,2,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);구글에 검색해도 왜 이런 증상이 발생하는지 찾아지지가 않아 문의 드립니다.bulid.gradle 설정은 다음과 같습니다.plugins { id 'java' id 'war' id 'org.springframework.boot' version '3.2.4' id 'io.spring.dependency-management' version '1.1.4'}group = 'jpabook'version = '0.0.1-SNAPSHOT'java { sourceCompatibility = '17'}configurations { compileOnly { extendsFrom annotationProcessor }}repositories { mavenCentral()}dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-devtools' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5-jakarta' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' testImplementation 'org.springframework.boot:spring-boot-starter-test'}tasks.named('test') { useJUnitPlatform()}
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
jsonignore와 지연로딩?
[섹션3 - 간단한 주문조회 V1 엔티티를 직접 노출] 강의에서[6:09] 처음에 api를 호출했을때는 양방향 연관관계 때문에 무한루프가 발생하였는데요, 이때는 지연로딩에 의한 이슈가 없었는데[11:07] JsonIgnore를 추가하여 순환 참조가 되는 상황을 제거했을때는 왜 지연로딩에 의한 이슈가 생기는 건가요??잘 동작하던 프록시객체가 JsonIgnore가 생겼다고 에러가 나는 상황이 잘 이해가 안되어 질문을 올립니다
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.2024-04-01T15:54:52.319+09:00 ERROR 11136 --- [ restartedMain] o.s.boot.SpringApplication : Application run failedorg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'initDb': Invocation of init method failed . . .Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : jpabook.jpashop.domain.Order.delivery -> jpabook.jpashop.domain.Delivery . . .Caused by: java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : jpabook.jpashop.domain.Order.delivery -> jpabook.jpashop.domain.Delivery . . .Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : jpabook.jpashop.domain.Order.delivery -> jpabook.jpashop.domain.Delivery at org.hibernate.engine.spi.CascadingActions$8.noCascade(CascadingActions.java:372) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:173) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:161) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:144) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:79) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1403) ~[hibernate-core-6.4.4.Final.jar:6.4.4.Final] ... 44 common frames omittedDeprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.For more on this, please refer to https://docs.gradle.org/8.6/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : jpabook.jpashop.domain.Order.delivery -> jpabook.jpashop.domain.DeliveryCaused by: java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : jpabook.jpashop.domain.Order.delivery -> jpabook.jpashop.domain.DeliveryCaused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : jpabook.jpashop.domain.Order.delivery -> jpabook.jpashop.domain.Delivery 에러메시지가 위와 같이 떠서 구글에서 해결방법들을 찾아서 해봤는데 다 해결되지 않았습니다 ㅠㅠ 혹시 어떻게 해야할까요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
batchsize와 in 쿼리 관련해서 질문드립니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]order와 orderItem의 예시의 경우 스트림의 map으로 order를 OrderDto로 바꾸는 과정에서 OrderDto의 생성자로 order 객체가 들어간 후 oderItem.getItem().getName()을 호출하면서 in 쿼리가 나가는 것 같은데 여기서 이해가 안 가는 부분이 있습니다. 조회된 order의 컬렉션이 매개변수로 넘어가는 것도 아니고 스트림은 원소를 하나씩 처리하는 것으로 알고 있는데 어떻게 조회된 모든 order의 아이디를 알고 in절 안에 넣을 수 있는 것인가요?강의를 보면 orderItem을 찾는 in 쿼리가 한 번만 나가는데 이건 첫 in 쿼리를 통해 모든 정보를 조회해서 이후에는 1차 캐시에서 조회 가능하기 때문에 그런 것인가요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
member엔티티와 order 엔티티의 조회 시 관계
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]json으로 return 할 때 궁금한 점이 있어서 질문드립니다.이전 강의에서 member 엔티티 자체를 json 타입으로 return 할 때는 orders(컬렉션)에 대해 무한루프가 걸리지 않았지만 order를 json 타입으로 return하게 되면 강의에서 처럼 여러 엔티티들에 의해 무한루프가 걸리게 됩니다.컬렉션인 데이터의 경우 무한루프에 걸리지 않는 이유가 무엇인가요??
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Name for argument of type [java.lang.Long] not specified, and parameter name information
Name for argument of type [java.lang.Long] not specified, and parameter name information 이 예외 뜨시는분들 @PathVariable(" ") 파라미터 이름 지정해주셔야할듯3.2이후 버전부터 파라미터 이름 자동으로 추론하지 않도록 변경됐대요
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
DTO 선언할 때 @AllArgsConstructor 붙여준 이유
DTO 선언 시 @AllArgsConstructor를 붙여주셨는데 그 이유가 궁금합니다.Jackson 라이브러리가 정상적으로 JSON 데이터를 객체에 바인딩 해주기 위해 모든 인스턴스 변수를 포함한 생성자가 필요해서 그런 것인가요?혹은 단순히 컨트롤러 메서드에서 DTO 데이터를 전체적으로 초기화하기 위함인가요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
주문 조회V3 에서 쿼리가 4개 나온다고 하는데, 2개만 나옵니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. @GetMapping("/api/v3/orders") public List<OrderDto> orderV3() { List<Order> orders = orderRepository.findAllWithItem(); for (Order order: orders) { System.out.println("order ref = " + order + " id = " + order.getId()); } List<OrderDto> result = orders.stream() .map(o -> new OrderDto(o)) .collect(Collectors.toList()); return result; } ... public List<Order> findAllWithItem() { return entityManager.createQuery( "select 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(); }이렇게 한 다음 v3 에게 요청을 넣었습니다.그 결과selecto1_0.order_id,d1_0.delivery_id,d1_0.city,d1_0.street,d1_0.zipcode,d1_0.status,m1_0.member_id,m1_0.city,m1_0.street,m1_0.zipcode,m1_0.username,o1_0.order_date,oi1_0.order_id,oi1_0.order_item_id,oi1_0.count,i1_0.item_id,i1_0.dtype,i1_0.name,i1_0.price,i1_0.stock_quantity,i1_0.artist,i1_0.etc,i1_0.author,i1_0.isbn,i1_0.actor,i1_0.director,oi1_0.order_price,o1_0.statusfromorders o1_0joinmember m1_0on m1_0.member_id=o1_0.member_idjoindelivery d1_0on d1_0.delivery_id=o1_0.delivery_idjoinorder_item oi1_0on o1_0.order_id=oi1_0.order_idjoinitem i1_0on i1_0.item_id=oi1_0.item_idorder ref = jpabook.jpashop.domain.Order@801a84d id = 1order ref = jpabook.jpashop.domain.Order@7be83ead id = 2 다음과 같은 SQL 쿼리를 보냈구요.그런데 4개가 아니라 2개라서 문의를 드립니다. 그런데 H2 DB에서 해당 쿼리를 입력하면 4개가 잘나옵니다.또한 포스트맨으로 받은 요청도 2개가 출력됩니다.[ { "orderId": 1, "name": "userA", "orderDate": "2024-03-18T23:29:35.545094", "orderStatus": "ORDER", "address": { "city": "서울", "street": "1", "zipcode": "11111" }, "orderItems": [ { "itemName": "JPA1 Book", "orderPrice": 10000, "count": 1 }, { "itemName": "JPA2 Book", "orderPrice": 20000, "count": 2 } ] }, { "orderId": 2, "name": "userB", "orderDate": "2024-03-18T23:29:35.555094", "orderStatus": "ORDER", "address": { "city": "부산", "street": "2", "zipcode": "22222" }, "orderItems": [ { "itemName": "Spring1 Book", "orderPrice": 20000, "count": 3 }, { "itemName": "Spring2 Book", "orderPrice": 40000, "count": 2 } ] } ]어떠한 것이 잘못되었는지 궁금합니다.
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
default_batch_fetch_size 질문
안녕하세요 강의를 들으며, 토이 프로젝트에 jpa를 적용해보려하는데 문제가 생겨 질문을 드리게 되었습니다. default_batch_fetch_size를 사용하게 되면 @OneToMany관계를 가질 때 미리 지정된 개수만큼 join을 해서 가져오는 것으로 이해를 했습니다.여기서 페이징 처리를 하고 싶은데, default_batch_fetch_size를 이용해 얻은 값에서 원하는 값만 조회를 하고 싶습니다. 현재 문제는 user와 tag(사용자가 관심있는 태그), post가 있을 때, user와 tag가 N:M 관계,tag와 post가 N:M 관계를 갖습니다.각각을 1:N, N:1로 나타내기 위해 연결 테이블을 만들었습니다. PostRepository에서 user가 관심있는 태그에 해당하는 게시물을 페이징으로 가져오고 싶은데 default_batch_fetch_size를 이용하면 직접 접근이 불가능할 것 같은데 이런 경우에는 어떻게 해결할 수 있을까요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
@Query 사용 시 연관테이블은 order by 가 불가한가요?
@Query("SELECT t From Team t join Fetch t.member m ORDER BY m.name desc")예를 들어 이런 식으로 Fetch join을 이용해서 연관테이블 리스트를 가져올 때에 정렬해서 가져오고 싶습니다.검색 등을 통해 해결해보려 했지만 방법을 모르겠네요 ㅠㅠ 만약 @Query가 안된다면 다른 방식으로 가져오는 방법이 있을까요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
깊은 연쇄 호출에 대한 성능 문제 질문입니다.
엔티티가 member, A,B,C 가 있습니다.엔티티 사이의 연관관계는 member, A : 일대다 양뱡향A,B : 일대다 양뱡향B,C : 일대다 양방향 관계입니다.이때 C 에 대한 조회를 하는데 있어서 memberId 도 같이 응답을 해줘야합니다.이런 경우 어떻게 처리하는게 좋을지에 대한 질문이 생겼습니다.memberId = C.getB().getA().getMember().getId() 이렇게 계속 호출을 해서 가져오는 방법은 성능상 안좋을 것 같아 실무에서는 어떻게 하시는지 궁금합니다.애초에 DB 설계가 안좋은건가요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
트랜잭션 락 질문
jpa 트랜잭션 락 기능중에 낙관적 락과 비관적 락이 있는데실제로 이 락을 실무에서도 많이 사용하는지 궁금합니다.인터넷 예시로 게시글 조회수 카운트나 좋아요 카운트 관리 할 때 많이 사용한다고 하는데조회수나 좋아요 카운트는 카운트가 실시간으로 정확히 맞을 필요는 없는데 굳이 락을 이용해서 관리를 해야만 하는지 의문점이 들기도 합니다.실제로 실무에서 많이 사용한다면, 좀 더 실무에 와 닿을 수 있는 케이스를 알려주시면 감사하겠습니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
batch size관련 질문
안녕하세요! spring jpa를 공부하다가 궁금증이 생겨서 질문을 올립니다. 혹시 jpa표준이 아닌 spring jpa를 쓰면 batch size를 적용할 필요가 없나요? spring jpa는 Page인터페이스와 Slice인터페이스를 사용하기에 질문을 드립니다!
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
default_batch_fetch_size 쿼리문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. select oi1_0.order_id, oi1_0.order_item_id, oi1_0.count, oi1_0.item_id, oi1_0.order_price from order_item oi1_0 where oi1_0.order_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)강의 4-4 페이징과 한계돌파 들으면서 똑같이 yml에 배치사이즈 100으로 하고 하던중확인해보니 in문에 강의처럼 order 데이터 2개 있으니 '?' 2개로 보여야하는데배치사이즈 설정한 수만큼 '?' 가 100개 이고 ,p6spy 보면 나머지 98개가 null로 들어갑니다..org.hibernate.orm.jdbc.bind: trace 하고 확인해봐도 여전한데하이버네이트나 머 다른게 업데이트후 저렇게 쿼리문 나가는게 정상이에요?아니면 다른 문제이면서 저렇게 쿼리문 나가는건 성능에 안 좋은 영향 있을까요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
업데이트는 그냥 dirty-checking을 이용하면 된다고 하셨는데..
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]강의에서 '"성능의 경우 조회에서 문제가 생기고, 생성이랑 수정은 성능 문제가 잘 발생하지 않는다"고 한 부분에서 궁금증이 생겼습니다! 업데이트의 경우 JPQL을 사용한 쿼리문을 통해 수정하는 방법이 있고, 엔티티를 싹 불러와서 dirty-cheking을 이용하는 방법이 있는걸로 알고 있습니다. 제 생각에는 뭔가 엔티티를 싹 불러오는 후자의 방법이 더 느릴거 같은데, 왜 후자를 그냥 쓰면 된다고 하신 이유가 궁금합니다!또 두 방식 중 어떤 상황에 무엇을 써야하는 지 기준이 있다면, 알려주시면 감사하겠습니다!