월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
aggregate 단위당 레파지토리 하나
안녕하세요 영한님 영한님 jpa강의를 쭉 들었었지만 aggregate 관련된 내용을 듣지 못한 것 같아 질문 남겨봅니다. aggregate 단위당 레파지토리 하나 라는 내용을 간혹 보게 되는데요 어떤 entity 가 여러 연관관계를 가졌다면 부모 entity의 repository만 작성해야 한다는 그런 뜻인지 궁금합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
통계성 데이터 조회
안녕하세요. 강사님 실무에서 통계성 데이터는 어떻게 처리하는지 궁금합니다. 통계성이면.. 객체가 연관관계가 없을 수도 있을 것이고, 대량의 데이터를 조회하기도 할 것 같은데 best practice나 권장 구현 방안이 있다면 설명 부탁드립니다.
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Entity를 DTO로 변환시키기
김영한님 JPA 강의를 듣다가 1장 마지막 부분 쯤에 Entity를 그대로 사용하지 말고 데이터를 전송할 때에는 DTO를 이용하라고 하셨는데, 테이블 끼리 연관관계가 많은 것들은 어떻게 변환시키나요? 가장 궁금한게 A에 List<B>,List<C>,List<D> 객체를 가지고 있는데 A의 DTO를 만든다고 한다면 B,C,D를 각자 또 BDTO,CDTO,DDTO 로 옮기고 나서 ADTO에 담는건가요?? MapStruct를 사용하려고 하는데, 혹시 Entity를 DTO로 변환하는 좋은 방법이 있는지 궁금합니다!
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
autocommit과 connection 획득 지연에 대해
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용] 안녕하세요. 먼저 좋은 강의 제작해주셔서 많은 도움이 되었고, 감사드립니다! osiv 를 설명해주신 강의에서, osiv가 켜져있으면 커넥션을 오래 물고 있어 트래픽이 많으면 장애가 발생할 수 있다고 하셨는데요. 같은 맥락으로 커넥션을 릴리즈하는 시점이 아닌 획득 하는 시점에서도 1. datasource에서 커넥션 autocommit을 false로 설정하고, (디폴트는 true) 2. 하이버네이트에게 트랜잭션 시작(그리고 종료) 시 set autocommit를 수행하지 않도록 해서(hibernate.connection.provider_disables_autocommit 옵션으로 하이버네이트에게 알려줌) 커넥션 획득을 지연시키고 불필요한 SET 문 실행을 없애, 결과적으로 커넥션 점유 시간을 줄이면서 리소스 사용과 쓰루풋 최적화가 가능하다고 합니다. 참고한 자료 - https://vladmihalcea.com/why-you-should-always-use-hibernate-connection-provider_disables_autocommit-for-resource-local-jpa-transactions/ - https://github.com/spring-projects/spring-boot/issues/9261 - https://pkgonan.github.io/2019/01/hibrnate-autocommit-tuning - https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/appendices/Configurations.html 그래서 위 자료들에 따르면 일반적인 스프링 부트 2 + 하이버네이트 조합을 쓰는 경우에는 datasource의 autocommit을 항상 false로 하는 것이 좋을 것 같은데(이 경우 hibernate.connection.provider_disables_autocommit는 자동으로 enable 설정됨), 혹시 이 설정에 대한 경험이 있으신지, 있으시다면 조심해야할 사이드이팩트는 없으셨는지 궁금해서 질문남겨봅니다. (늦더라도 영한님께서 직접 답변해주시면 좋을 것 같습니다^^) 감사합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
컨트롤러 파라미터와 DTO에 대한 질문입니다.
[질문 내용]안녕하세요. 컨트롤러 파라미터에 대해서 질문이 있습니다. 보통 컨트롤러에서 @RequestBody로 DTO를 받는데요. 개인 프로젝트를 진행하면서 ,DTO 클래스를 계속 생성하게 되면 DTO파일도 많아지는 경향이 있다고 느꼈습니다. 전달받아야 할 파라미터가 1개인 경우, DTO클래스를 생성하는 것 대신, @RequestParam 혹은 Map을 활용하는 방법이 있는데요. @RequestParam을 사용하면 옵션을 줄 수 있다는 점, 올바르지 않은게 오면 400 코드를 준다는 점 정도가 다른 점이라고 생각합니다. 둘이 큰 차이가 없다고 생각하는데, Map을 사용하는 것에 대해 부정적인 의견도 많이 있는 것 같습니다. 한 개의 파라미터를 받기 위해 어느 방법을 사용하는 것이 효율적일까요? 상황마다 다른지, 보통 어떤식으로 처리하는지 궁금합니다. 감사합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
DTO, VO, DAO, Repository에 관련한 질문드립니다.
안녕하세요 강의 정말 유익하게 잘 듣고 있습니다. 실무로 스프링을 접하며 강의를 같이 들으며 진행하고 있는데 들으면서 너무 헷갈리는 부분이 있어 문의드립니다. 1. DTO 와 VO의 차이 그리고 실무에서 어떤경우에 사용하는지 차이 DTO = 전송되는 데이터를 담는 객체 VO = getter/setter 로만 구성된 불변하는 데이터를 담는 객체 라고 표현이 되는데, 너무 와닿지가 않아서 정확한 차이점을 질문드리고 싶습니다. 추가로, 찾아본 예제들에서는 DTO와 VO를 혼합하여 사용하거나 아예 한쪽만 사용하는경우가 혼재되어 많이 헷갈립니다 실무에서는 어떤경우에 어떤 구조체를 사용하는건지 문의드립니다. 2. DAO와 Repository 의 차이점을 문의드립니다. 제가 알기론, 둘다 DB와 소통을 하는 로직을 구현하는건 같지만 DAO는 Data Persistence 를 구체화 한 것이고, 테이블과 더 Low level에서 연관성을 가지고 있고, Repository는 DAO보다 더 High level로 repository안에 여러개의 dao를 사용하여 구현하기도 하는것으로 알고 있습니다. 다만, 예제들을 찾아보면 누구는 DAO로만 구성하여 사용하고, 누구는 Repository만 구현하여 사용하여 실무에서 어떤경우에 DAO와 Repository를 사용하는지가 너무 헷갈립니다. DAO와 Repository가 실무에서 어느때에 사용되는건지 문의도 같이 드리고 싶습니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
DTO와 엔티티의 변환 작업은 어느 계층에서 하는게 좋은지에 대해 질문드립니다.
DTO 객체에서 엔티티로 또는 엔티티에서 DTO로 변환하는 작업은 컨트롤러에서 해야할까요? 아니면 서비스 단에서 해야할까요? 어느 계층에서 하는게 좋나요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
insert sql batch
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요 영한님! 강의 정말 잘 보고 있습니다. 궁금한 점은 조회할 때는 join fetch나 default_batch_fetch_size를 통해 성능 최적화를 하는데, 샘플 데이터를 넣을 때의 쿼리를 보니까 많은 쿼리가 나가는 것을 확인 했습니다. orderItem들이 생성 될 때 여러 번의 쿼리가 아니라 한 번의 쿼리로 실행되게 하는 방법이 있을까요?? insert batch 등을 검색해봤는데 잘 적용이 되지 않아 질문 남깁니다! insert into member (city, street, zipcode, name, member_id) values ('서울', '1', '1111', 'userA', 1); insert into item (name, price, stock_quantity, author, isbn, dtype, item_id) values ('JPA1 BOOK', 10000, 100, NULL, NULL, 'B', 2); insert into item (name, price, stock_quantity, author, isbn, dtype, item_id) values ('JPA2 BOOK', 20000, 100, NULL, NULL, 'B', 3); insert into delivery (city, street, zipcode, delivery_status, delivery_id) values ('서울', '1', '1111', NULL, 5); insert into orders (delivery_id, member_id, order_date, status, order_id) values (5, 1, '2022-06-08T16:23:38.605+0900', 'ORDER', 4); insert into order_item (count, item_id, order_id, order_price, order_item_id) values (1, 2, 4, 10000, 6); insert into order_item (count, item_id, order_id, order_price, order_item_id) values (2, 3, 4, 20000, 7); update item set name='JPA1 BOOK', price=10000, stock_quantity=99, author=NULL, isbn=NULL where item_id=2; update item set name='JPA2 BOOK', price=20000, stock_quantity=98, author=NULL, isbn=NULL where item_id=3;
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
@JsonIgnore 는 엔티티에서 안붙여도 되는걸까요??
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용] 강의 잘 보고 있습니다 감사합니다! 엔티티는 json으로 반환하지 않는 걸로 알고 있고 그렇게하면 안된다는 걸 이해했습니다. 그렇다면, 엔티티를 json으로 반환하지 않는 방식으로 설계를 한다면 @JsonIgnore 는 양방향 관계에서도 안붙여도 될까요??
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
distinct 질문 드립니다!
일대다 컬렉션 페치 조인 조회의 경우 팀A인 멤버가 1, 2, 3이면 DB는 멤버를 기준으로 조인을 해서 팀A인 row가 3개가 생기고 하이버네이트는 이를 받아와서 리스트로 반환(getResultList)해줄 때 리스트에 팀 A 엔티티를 3개 담아줍니다. 여기서 각각의 엔티티는 PK 값이 같기 때문에 서로 같은 엔티티를 참조합니다. (이렇게 이해를 했습니다!) 그러면 쿼리 횟수에 영향을 주는 건 페치 조인이고, distinct는 리스트에 중복 엔티티만 제거하는 역할만 하는 것 같은데 (select 다음 distinct가 추가되는 것 외에는 차이가 없음) 속도적인 면에서는 별 차이가 없는 것이 맞을까요??
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
"status": 500 오류 관련 질문입니다.
안녕하세요 현재 간단한 주문조회 V4 : JPA에서 DTO로 바로조회 부분을 수강 중에 생긴 오류입니다. 아래 그림과 같이 오류가 뜨는데, 서버가 실행 되지 않아 생긴 오류는 아닌 것 같습니다. package jpabook.jpashop.api;import jpabook.jpashop.domain.Address;import jpabook.jpashop.domain.Order;import jpabook.jpashop.domain.OrderStatus;import jpabook.jpashop.repository.OrderRepository;import jpabook.jpashop.repository.OrderSearch;import jpabook.jpashop.repository.OrderSimpleQueryDto;import lombok.Data;import lombok.RequiredArgsConstructor;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.time.LocalDateTime;import java.util.List;import java.util.stream.Collectors;import static java.util.stream.Collectors.toList;/** * xToOne * Order * Order -> Member * Order -> Delivery */@RestController@RequiredArgsConstructorpublic class OrderSimpleApiController { private final OrderRepository orderRepository; @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; } @GetMapping("/api/v2/simple-orders") public List<SimpleOrderDto> ordersV2() { //ORDER 2개 //N + 1 -> 1 + 회원 N(2) + 배송 N List<Order> orders = orderRepository.findAllByString(new OrderSearch()); List<SimpleOrderDto> result = orders.stream() .map(o -> new SimpleOrderDto(o)) .collect(toList()); return result; } @GetMapping("/api/v3/simple-orders") public List<SimpleOrderDto> ordersV3() { List<Order> orders = orderRepository.findAllWithMemberDelivery(); List<SimpleOrderDto> result = orders.stream() .map(o -> new SimpleOrderDto(o)) .collect(Collectors.toList()); return result; } @GetMapping("/api/v4/simple-orders") public List<OrderSimpleQueryDto> ordersV4() { return orderRepository.findOrderDtos(); } @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(); } }} package jpabook.jpashop.repository;import jpabook.jpashop.domain.Order;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Repository;import org.springframework.util.StringUtils;import javax.persistence.EntityManager;import javax.persistence.TypedQuery;import javax.persistence.criteria.*;import java.util.ArrayList;import java.util.List;@Repository@RequiredArgsConstructorpublic class OrderRepository { private final EntityManager em; public void save(Order order) { em.persist(order); } public Order findOne(Long id) { return em.find(Order.class, id); } public List<Order> findAllByString(OrderSearch orderSearch) { //language=JPAQL String jpql = "select o From Order o join o.member m"; boolean isFirstCondition = true;//주문 상태 검색 if (orderSearch.getOrderStatus() != null) { if (isFirstCondition) { jpql += " where"; isFirstCondition = false; } else { jpql += " and"; } jpql += " o.status = :status"; }//회원 이름 검색 if (StringUtils.hasText(orderSearch.getMemberName())) { if (isFirstCondition) { jpql += " where"; isFirstCondition = false; } else { jpql += " and"; } jpql += " m.name like :name"; } TypedQuery<Order> query = em.createQuery(jpql, Order.class) .setMaxResults(1000); //최대 1000건 if (orderSearch.getOrderStatus() != null) { query = query.setParameter("status", orderSearch.getOrderStatus()); } if (StringUtils.hasText(orderSearch.getMemberName())) { query = query.setParameter("name", orderSearch.getMemberName()); } return query.getResultList(); } /** * JPA Criteria */ public List<Order> findAllByCriteria(OrderSearch orderSearch) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Order> cq = cb.createQuery(Order.class); Root<Order> o = cq.from(Order.class); Join<Object, Object> m = o.join("member", JoinType.INNER); List<Predicate> criteria = new ArrayList<>(); //주문 상태 검색 if (orderSearch.getOrderStatus() != null) { Predicate status = cb.equal(o.get("status"), orderSearch.getOrderStatus()); criteria.add(status); } //회원 이름 검색 if (StringUtils.hasText(orderSearch.getMemberName())) { Predicate name = cb.like(m.<String>get("name"), "%" + orderSearch.getMemberName() + "%"); criteria.add(name); } cq.where(cb.and(criteria.toArray(new Predicate[criteria.size()]))); TypedQuery<Order> query = em.createQuery(cq).setMaxResults(1000); //최대 1000건 return query.getResultList(); } 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();} 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(); }} package jpabook.jpashop.repository;import jpabook.jpashop.domain.Address;import jpabook.jpashop.domain.OrderStatus;import lombok.Data;import java.time.LocalDateTime;@Data public class OrderSimpleQueryDto { private Long orderId; private String name; private LocalDateTime orderDate; private OrderStatus orderStatus; private Address address; public OrderSimpleQueryDto(Long orderId, String name, LocalDateTime orderDate, OrderStatus orderStatus, Address address) { this.orderId = orderId; this.name = name; this.orderDate = orderDate; this.orderStatus = orderStatus; this.address = address; } } 2022-05-31 02:13:36.433 ERROR 1563 --- [nio-8080-exec-4] o.h.hql.internal.ast.ErrorTracker : Unable to locate class [jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto] [cause=org.hibernate.boot.registry.classloading.spi.ClassLoadingException: Unable to load class [jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto]] 2022-05-31 02:13:36.436 ERROR 1563 --- [nio-8080-exec-4] o.h.hql.internal.ast.ErrorTracker : Unable to locate class [jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto] [cause=org.hibernate.boot.registry.classloading.spi.ClassLoadingException: Unable to load class [jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto]] org.hibernate.hql.internal.ast.DetailedSemanticException: Unable to locate class [jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto] at org.hibernate.hql.internal.ast.tree.ConstructorNode.resolveConstructor(ConstructorNode.java:177) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.ast.tree.ConstructorNode.prepare(ConstructorNode.java:144) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.ast.HqlSqlWalker.processConstructor(HqlSqlWalker.java:1271) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectExpr(HqlSqlBaseWalker.java:2409) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectExprList(HqlSqlBaseWalker.java:2275) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectClause(HqlSqlBaseWalker.java:1534) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:611) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:339) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:287) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:276) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:636) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:748) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:848) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:114) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:362) ~[spring-orm-5.3.19.jar:5.3.19] at com.sun.proxy.$Proxy110.createQuery(Unknown Source) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311) ~[spring-orm-5.3.19.jar:5.3.19] at com.sun.proxy.$Proxy110.createQuery(Unknown Source) ~[na:na] at jpabook.jpashop.repository.OrderRepository.findOrderDtos(OrderRepository.java:105) ~[classes/:na] at jpabook.jpashop.repository.OrderRepository$$FastClassBySpringCGLIB$$9808961b.invoke(<generated>) ~[classes/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.19.jar:5.3.19] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.19.jar:5.3.19] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.19.jar:5.3.19] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.19.jar:5.3.19] at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.19.jar:5.3.19] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.19.jar:5.3.19] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.19.jar:5.3.19] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.19.jar:5.3.19] at jpabook.jpashop.repository.OrderRepository$$EnhancerBySpringCGLIB$$3bdf9949.findOrderDtos(<generated>) ~[classes/:na] at jpabook.jpashop.api.OrderSimpleApiController.ordersV4(OrderSimpleApiController.java:70) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.19.jar:5.3.19] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.19.jar:5.3.19] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.19.jar:5.3.19] at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) ~[tomcat-embed-core-9.0.62.jar:4.0.FR] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.19.jar:5.3.19] at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.62.jar:4.0.FR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.19.jar:5.3.19] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.19.jar:5.3.19] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.19.jar:5.3.19] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.19.jar:5.3.19] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.19.jar:5.3.19] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.19.jar:5.3.19] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na] 2022-05-31 02:13:36.441 ERROR 1563 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate class [jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto] [select new jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto(o.id, m.name, o.orderDate, o.status, d.address) from jpabook.jpashop.domain.Order o join o.member m join o.delivery d]; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate class [jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto] [select new jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto(o.id, m.name, o.orderDate, o.status, d.address) from jpabook.jpashop.domain.Order o join o.member m join o.delivery d]] with root cause org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate class [jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto] [select new jpabook.jpashop.repository.order.simplequery.OrderSimpleQueryDto(o.id, m.name, o.orderDate, o.status, d.address) from jpabook.jpashop.domain.Order o join o.member m join o.delivery d] at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:74) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.ast.ErrorTracker.throwQueryException(ErrorTracker.java:93) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:282) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:636) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:748) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:848) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:114) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:362) ~[spring-orm-5.3.19.jar:5.3.19] at com.sun.proxy.$Proxy110.createQuery(Unknown Source) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311) ~[spring-orm-5.3.19.jar:5.3.19] at com.sun.proxy.$Proxy110.createQuery(Unknown Source) ~[na:na] at jpabook.jpashop.repository.OrderRepository.findOrderDtos(OrderRepository.java:105) ~[classes/:na] at jpabook.jpashop.repository.OrderRepository$$FastClassBySpringCGLIB$$9808961b.invoke(<generated>) ~[classes/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.19.jar:5.3.19] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.19.jar:5.3.19] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.19.jar:5.3.19] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.19.jar:5.3.19] at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-5.3.19.jar:5.3.19] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.19.jar:5.3.19] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.19.jar:5.3.19] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.19.jar:5.3.19] at jpabook.jpashop.repository.OrderRepository$$EnhancerBySpringCGLIB$$3bdf9949.findOrderDtos(<generated>) ~[classes/:na] at jpabook.jpashop.api.OrderSimpleApiController.ordersV4(OrderSimpleApiController.java:70) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.19.jar:5.3.19] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.19.jar:5.3.19] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.19.jar:5.3.19] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.19.jar:5.3.19] at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) ~[tomcat-embed-core-9.0.62.jar:4.0.FR] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.19.jar:5.3.19] at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.62.jar:4.0.FR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.19.jar:5.3.19] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.19.jar:5.3.19] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.19.jar:5.3.19] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.19.jar:5.3.19] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.19.jar:5.3.19] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.19.jar:5.3.19] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.62.jar:9.0.62] at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na] 오류내용은 이러합니다. OrderSimpleApiController 클래스에 @GetMapping("/api/v4/simple-orders")public List<OrderSimpleQueryDto> ordersV4() { return orderRepository.findOrderDtos();} orderRepository 가 잘못된 것일까요?.. 오류 내용을 보면 저 부분을 얘기하는 것 같은데 어떤 부분이 잘못되었는지 이해가 잘 안됩니다 ㅜㅠ 도움 부탁드립니다!!!!..
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
postman사용법
안녕하세요! 현재 회원등록 api 강의를 듣고 있는 중인데 postman 설치 하여 사용하는 내용이 나옵니다. postman 처음 사용 과정은 따로 강의로 들을 수 있는게 없나요?! 스프링부트와 jap활용1 강의를 듣고 바로 넘어왔는데 내용이 따로 없어서요!!! ㅜㅜㅜ headers 부분에 Content-Type 은 직접 입력해서 넣었구요 .. body에 내용을 넣어 send를 했는데 밑에 내용처럼 오류?가 뜹니다 ㅠㅠ 무슨 문제일까요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
쿼리 로그
application.properties에서 여러 설정을 추가해도 강사님처럼 예쁘게 쿼리가 정렬되어 나오지 않아서 가독성이 떨어지는데요, 1. 어떤 것을 추가하거나 주석처리를 해야할까요? 2. 그리고 같은 쿼리가 왜 두번 찍히는지 궁금합니다. 현재 상황
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
@Data v2
v1에서 CreateMemberResponse는 final 키워드, @NotNull이 모두 없으므로 id를 받는 생성자를 새로 생성해주었습니다. v2인 CreateMemberRequest에서도 final 키워드, @NotNull이 모두 없으므로 id를 받는 생성자를 만들어 주어야 할 것 같은데 이 경우 생성 안해준 이유가 궁금합니다. @Datastatic class CreateMemberRequest{ @NotEmpty private String name;}
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
@Data 생성자
@Data 는 롬복 어노테이션으로 @toString + @getter + @setter + @RequiredArgsConstructor + @EqualsAndHashCode 를 합친 어노테이션으로 알고 있습니다. 그래서 @Data를 사용했을 때 생성자, getter, setter...를 따로 안 적어주어도 되는데 강의 8분22초에서는 생성자를 따로 생성했습니다. @PostMapping("/api/v1/members")public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member) { Long id = memberService.join(member); return new CreateMemberResponse(id);}@Datastatic class CreateMemberResponse{ private Long id; public CreateMemberResponse(Long id) { this.id = id; }} 왜 만들어 주었는지 궁금합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
스프링부트 2.6.7, java 8, gradle 7.4.X querydsl 설정 방법 공유
시행착오 끝에 성공해가지고 공유합니다. (저의 프로젝트 gradle 버전은 7.4대입니다.) 첫번째로 build.gradle 입니다. 의존성에 나머지 부분은 무시하셔도 되고 10번대가 querydsl설정부분입니다. /* 10-1. querydsl version 정보 추가 */ buildscript { ext { queryDslVersion = "5.0.0"; } } plugins { id 'org.springframework.boot' version '2.6.7' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' id 'war' /* 10-2. querydsl plugin 추가 */ id "com.ewerk.gradle.plugins.querydsl" version "1.0.10" } group = 'com.shop' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' /* 10-3. querydsl */ configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { /* 1. web */ implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' /* 2. 배포시 내장톰캣을 사용하지 않을거라는 dependency */ providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' /* 3. lombok */ compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' /* 4. devtools */ runtimeOnly 'org.springframework.boot:spring-boot-devtools' /* 5. thymeleaf */ implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' /* 6. mybatis */ implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.3' /* 7. MariaDB */ runtimeOnly 'org.mariadb.jdbc:mariadb-java-client' /* 8. JDBC */ implementation 'org.springframework.boot:spring-boot-starter-jdbc' /* 9. JPA */ implementation 'org.springframework.boot:spring-boot-starter-data-jpa' /* 10-4. querydsl dependencies 추가 */ implementation "com.querydsl:querydsl-jpa:${queryDslVersion}" annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}" /* 11. thymeleaf-layout-dialect */ implementation group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect', version: '3.0.0' /* 12. spring-boot-starter-security */ implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security' /* 13. validation(Bean Validation) */ implementation 'org.springframework.boot:spring-boot-starter-validation' /* 14. modelmapper */ implementation group: 'org.modelmapper', name: 'modelmapper', version: '2.3.9' /* 15. thymeleaf-extras-springsecurity5 */ implementation group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-springsecurity5' /* 16. spring-security-test */ testImplementation group: 'org.springframework.security', name: 'spring-security-test' } tasks.named('test') { useJUnitPlatform() } /* 10-5. querydsl에서 사용할 경로 지정*/ def querydslDir = "src/main/generated" /* 10-6. JPA사용 여부와 사용할 경로를 지정*/ querydsl { jpa = true querydslSourcesDir = querydslDir } /* 10-7. build시 사용할 SourceSet 추가 */ sourceSets { main.java.srcDir querydslDir } /* 10-8. querydsl이 complieClasspath를 상속하도록 설정 */ configurations { querydsl.extendsFrom compileClasspath } /* 10-9. querydsl 컴파일시 사용할 옵션 설정 */ compileQuerydsl { options.annotationProcessorPath = configurations.querydsl } -> build.gradle에 이렇게 적구요. -> 프로젝트 우클릭 gradle -> represh gradle project를 한번 해주고 진행합니다. 두번째 -> gradle task -> build -> classes를 실행 -> src/main 하위에 generated라는 폴더가 생기고 그 하위에 Q파일이 생긴걸 볼 수 있다. -> 하지만 추가로 더 해줘야 할 작업이 있다. 프로젝트에서 저 경로를 추가해줘야 위에서 사용할 수 있다. 아무 컨트롤러에서 Q파일을 불러올려고하면 찾지를 못한다. 그래서 경로를 추가해줘야한다. -> 프로젝트 우클릭 -> Build Path -> Configure Build Path 로 들어간다. -> Java Build Path -> Source 탭에 보면 프로젝트에 우리가 추가한 generated 폴더가 보이지 않는다. -> Add Folder... 클릭 -> 우리가 만든 generated도 체크를 해주고 확인을 눌르고 Apply하면 프로젝트 위에도 우리가만든 q파일이 들어있는 폴더 generated가 생긴다. -> 이제 아무 컨트롤러에 들어가서 Q를 치고 자동완성을 해보면 접근할 수 있는걸 볼 수 있고 이제 다음 강의를 들으러 가면된다. 끝..... 이상 스프링부트 2.6.7에서 querydsl 적용 방법이었습니다. 추가로 보통 이것저것 찾아봤는데 java 11버전으로 많이들 하시더라구요 근데 제꺼는 java8도 돌아갑니다 (제가 java8....)
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
OneToMany 연관관계에서 상위 entity update시 신규 하위 entity 저장
상위 entity update시 하위 entity의 신규 값이 오면 저장을 시키는데 신규 저장 된 하위 entity Id값이 필요합니다. save를 안 시키면 id 값이 안 넘어오고 save를 시키면 동일한 하위 entity가 두개 넘어오는 데 어떤 식으로 처리 해야할까요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Repository, Service에 따른 , @Transaction(readOnly=ture)에 따른 쿼리 차이에 대해 질문드립니다.
@Entity @Getter @Setter public class Category { @Id @Column(name="CATEGORY_ID") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="MEMBER_ID") private Member member; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="PARENT_ID") private Category parent; @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL) private List<Category> child = new ArrayList<>(); } @Repository public class CategoryRepository { private final EntityManager em; public List<Category> findAll(){ return em.createQuery("select c from Category c", Category.class) .getResultList(); } } @Service @Transactional @RequiredArgsConstructor public class CategoryService { private final CategoryRepository categoryRepository; @Transaction <-- 이부분 //@Transaction(readOnly=true) <-- 이부분 public List<Category> findAll() {return categoryRepository.findAll(); } } @RestController @RequiredArgsConstructor public class CategoryApiController { private final CategoryService categoryService; private final CategoryRepository categoryRepository; private final MemberService memberService; @GetMapping("/api/v1/categories") public Result getCategory(@RequestParam(required = false, value = "id") String memberId){ List<Category> categories = categoryService.findAll(); <-- 이부분 // List<Category> categories = categoryRepository.findAll(); <-- 이부분 List<CategoryDto> categoryDtos = categories.stream() .map(c -> new CategoryDto(c)) .collect(Collectors.toList()); return new Result(categoryDtos.size(), categoryDtos); } @Data @AllArgsConstructor static class CategoryDto{ public CategoryDto(Long id, String name) { this.id = id; this.name = name; } public CategoryDto(Category category) { this.id = category.getId(); this.name = category.getName(); this.child = category.getChild().stream() .map(c -> new CategoryDto(c.getId(),c.getName())) .collect(Collectors.toList()); } private Long id; private String name; private List<CategoryDto> child; private Long parentId; } } categoryRepository.findAll()를 호출 했을 때 2022-05-12 23:35:46.474 DEBUG 18928 --- [nio-9090-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor 2022-05-12 23:35:46.527 INFO 18928 --- [nio-9090-exec-2] p6spy : #1652366146527 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_ select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_; 2022-05-12 23:35:46.539 INFO 18928 --- [nio-9090-exec-2] p6spy : #1652366146539 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id in (?, ?, ?, ?, ?, ?, ?, ?) select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id in (6, 7, 8, 9, 10, 11, 12, 13); 2022-05-12 23:35:46.566 DEBUG 18928 --- [nio-9090-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor categoryService.findAll() 을 호출 했을 때 1)@Transaction(readOnly = true) 2022-05-12 23:31:45.235 DEBUG 18388 --- [nio-9090-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor 2022-05-12 23:31:45.258 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(72969494<open>)] for JPA transaction 2022-05-12 23:31:45.258 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.blog.demo.service.CategoryService.findAllRootCategories]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly 2022-05-12 23:31:45.261 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@675de2b1] 2022-05-12 23:31:45.292 INFO 18388 --- [nio-9090-exec-1] p6spy : #1652365905292 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_ select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_; 2022-05-12 23:31:45.301 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit 2022-05-12 23:31:45.301 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(72969494<open>)] 2022-05-12 23:31:45.301 INFO 18388 --- [nio-9090-exec-1] p6spy : #1652365905301 | took 0ms | commit | connection 1| url jdbc:h2:tcp://localhost/~/blog ; 2022-05-12 23:31:45.302 DEBUG 18388 --- [nio-9090-exec-1] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction 2022-05-12 23:31:45.303 INFO 18388 --- [nio-9090-exec-1] p6spy : #1652365905303 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id in (?, ?, ?, ?, ?, ?, ?, ?) select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id in (6, 7, 8, 9, 10, 11, 12, 13); 2022-05-12 23:31:45.329 DEBUG 18388 --- [nio-9090-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor 2)@Transaction 2022-05-12 23:37:14.348 DEBUG 19206 --- [nio-9090-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor 2022-05-12 23:37:14.369 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1468362384<open>)] for JPA transaction 2022-05-12 23:37:14.369 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.blog.demo.service.CategoryService.findAllRootCategories]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 2022-05-12 23:37:14.371 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@4209a22e] 2022-05-12 23:37:14.402 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234402 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_ select category0_.category_id as category1_0_, category0_.member_id as member_i3_0_, category0_.name as name2_0_, category0_.parent_id as parent_i4_0_ from category category0_; 2022-05-12 23:37:14.414 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit 2022-05-12 23:37:14.414 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(1468362384<open>)] 2022-05-12 23:37:14.418 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234418 | took 0ms | commit | connection 1| url jdbc:h2:tcp://localhost/~/blog ; 2022-05-12 23:37:14.419 DEBUG 19206 --- [nio-9090-exec-2] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction 2022-05-12 23:37:14.420 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234420 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=? select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=6; 2022-05-12 23:37:14.421 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234421 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=? select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=7; 2022-05-12 23:37:14.423 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234423 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=? select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=8; 2022-05-12 23:37:14.424 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234424 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=? select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=9; 2022-05-12 23:37:14.424 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234424 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=? select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=10; 2022-05-12 23:37:14.424 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234424 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=? select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=11; 2022-05-12 23:37:14.425 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234425 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=? select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=12; 2022-05-12 23:37:14.425 INFO 19206 --- [nio-9090-exec-2] p6spy : #1652366234425 | took 0ms | statement | connection 1| url jdbc:h2:tcp://localhost/~/blog select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=? select child0_.parent_id as parent_i4_0_1_, child0_.category_id as category1_0_1_, child0_.category_id as category1_0_0_, child0_.member_id as member_i3_0_0_, child0_.name as name2_0_0_, child0_.parent_id as parent_i4_0_0_ from category child0_ where child0_.parent_id=13; 2022-05-12 23:37:14.456 DEBUG 19206 --- [nio-9090-exec-2] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor 안녕하세요. 좋은 강의 감사합니다. 강의에서 Order로 api를 만들어주셔서 저는 개인적으로 Category에 대해서 api를 간단하게 만들어보면서 테스트를 몇가지 진행했었는데요. Controller에서 Category의 child를 지연로딩을 통해서 가져올 때 아래 세가지의 경우에 따라 쿼리문이 달라지는 현상을 겪었습니다. 위 코드에서 `<-- 이부분` 으로 표시된 부분을 참고해주시면 감사하겠습니다. 1. Repository로 최초에 Category를 가져올 때에는 in 쿼리가 잘 나갔고, 2. Controller에서 Service로 최초에 Category를 가져올 때는 Service의 해당 메소드에 @Transaction 일떄에는 N+1 문제가 발생하고 3. readOnly=true 일때에는 in 쿼리로 잘 가지고 오는데 이 상황에대해서 이해가 잘 되지 않아 질문 드리게 됐습니다. 3가지 상황 모두 OSIV가 켜져있고, default_batch_fetch_size: 100인 상황입니다. 각각 상황에 대해서 왜 in 쿼리가 나가고 안나가는지에 대해서 설명해주실 수 있을까요? 감사합니다. Repository와 Service차이의 경우 OSIV가 켜져있기 때문에 Controller에 돌아와서도 영속성 컨텍스트가 유지되는게 동일 할텐데 왜 쿼리 차이가 있는지 모르겠고 readOnly=true인 경우, 영속성 컨텍스트의 내용을 플러시하지 않는 것으로 알고있는데 플러시 여부와 지연로딩시 쿼리가 다르게 나가는 것은 상관이 없을 것 같은데 왜 차이가 나는지 파악이 안되고 있습니다. * 트랜잭션 로그를 찍어보니 Repository에서는 transaction을 생성하지 않고 트랜잭션없는 읽기를 진행하는 것으로 보이고 Service에서는 readOnly인 트랜잭션을 생성하냐/아니냐의 차이로 보입니다.
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
OneToMany 페치 조인 문제
현재 그룹 조회 API를 구현하고 있습니다. 메신저 앱 처럼 그룹 조회시 그룹 아이디, 그룹 이름, 그룹 이미지, 그룹에 속해있는 멤버들 (컬렉션)을 조회해 와야합니다. 여기서 강의의 V3 내용처럼 1 + N 문제를 해결하기 위해서 다음과 같이 페치 조인을 사용하여 쿼리문을 작성하였습니다. TeamRepository.java @Transactional(readOnly = true) public interface TeamRepository extends JpaRepository<Team, Long> { @Query("select distinct t from Team t" + " join fetch t.id id" + " join fetch t.groupName gn" + " join fetch t.imageUrl iu" + " join fetch t.teamMembers tm" + " join fetch tm.member m" + " where tm.id = :id") List<SearchGroupResponse> findGroupInfoWithMembers(@Param("id") Long id); } `Team.java` @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Team extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private Member member; @Column(length = 30) private String groupName; @Lob private String imageUrl; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "place_id") private Place place; @OneToMany(mappedBy = "team", cascade = CascadeType.ALL) private final List<TeamMember> teamMembers = new ArrayList<>(); private LocalDateTime date; } TeamMember.java @Entity @Getter @Table(name = "GroupMember") @NoArgsConstructor(access = AccessLevel.PROTECTED) public class TeamMember extends BaseEntity { @ManyToOne(fetch = LAZY) @JoinColumn(name = "member_id") private Member member; @ManyToOne(fetch = LAZY) @JoinColumn(name = "team_id") private Team team; @Column(length = 100) private String curLocate; private char arrived; public TeamMember(Member member, Team team) { this.member = member; this.team = team; } } 강의 V3-1 과 같이 컬랙션 데이터는 지연 로딩과 BatchSize를 적용하여 성능 최적화를 해줘야 된다고 배웠지만 일단은 V3를 적용해 보고 개선해 보고자 이렇게 코드를 작성해 보았습니다. 하지만 다음과 같은 에러가 발생하였고 이를 해결하고자 여러 구글링을 해보았지만 해답을 찾지 못하여 질문 남겨봅니다. org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'promiseController' defined in file [/Users/sanha/SpringStudy/promisor/out/production/classes/promisor/promisor/domain/promise/api/PromiseController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'promiseService' defined in file [/Users/sanha/SpringStudy/promisor/out/production/classes/promisor/promisor/domain/promise/service/PromiseService.class]: Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'teamRepository' defined in promisor.promisor.domain.team.dao.TeamRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)! Reason: Validation failed for query for method public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)!; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)! at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.15.jar:5.3.15] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.15.jar:5.3.15] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.3.jar:2.6.3] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) ~[spring-boot-2.6.3.jar:2.6.3] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:414) ~[spring-boot-2.6.3.jar:2.6.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:302) ~[spring-boot-2.6.3.jar:2.6.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) ~[spring-boot-2.6.3.jar:2.6.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) ~[spring-boot-2.6.3.jar:2.6.3] at promisor.promisor.PromisorApplication.main(PromisorApplication.java:12) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na] at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.6.3.jar:2.6.3] Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'promiseService' defined in file [/Users/sanha/SpringStudy/promisor/out/production/classes/promisor/promisor/domain/promise/service/PromiseService.class]: Unsatisfied dependency expressed through constructor parameter 2; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'teamRepository' defined in promisor.promisor.domain.team.dao.TeamRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)! Reason: Validation failed for query for method public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)!; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)! at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1389) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-5.3.15.jar:5.3.15] ... 24 common frames omitted Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'teamRepository' defined in promisor.promisor.domain.team.dao.TeamRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)! Reason: Validation failed for query for method public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)!; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)! at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1389) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-5.3.15.jar:5.3.15] ... 38 common frames omitted Caused by: org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)! Reason: Validation failed for query for method public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)!; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)! at org.springframework.data.repository.query.QueryCreationException.create(QueryCreationException.java:101) ~[spring-data-commons-2.6.1.jar:2.6.1] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:106) ~[spring-data-commons-2.6.1.jar:2.6.1] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$mapMethodsToQuery$1(QueryExecutorMethodInterceptor.java:94) ~[spring-data-commons-2.6.1.jar:2.6.1] at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na] at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133) ~[na:na] at java.base/java.util.Collections$UnmodifiableCollection$1.forEachRemaining(Collections.java:1056) ~[na:na] at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) ~[na:na] at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na] at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na] at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[na:na] at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na] at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[na:na] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.mapMethodsToQuery(QueryExecutorMethodInterceptor.java:96) ~[spring-data-commons-2.6.1.jar:2.6.1] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lambda$new$0(QueryExecutorMethodInterceptor.java:86) ~[spring-data-commons-2.6.1.jar:2.6.1] at java.base/java.util.Optional.map(Optional.java:258) ~[na:na] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.<init>(QueryExecutorMethodInterceptor.java:86) ~[spring-data-commons-2.6.1.jar:2.6.1] at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:364) ~[spring-data-commons-2.6.1.jar:2.6.1] at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:322) ~[spring-data-commons-2.6.1.jar:2.6.1] at org.springframework.data.util.Lazy.getNullable(Lazy.java:230) ~[spring-data-commons-2.6.1.jar:2.6.1] at org.springframework.data.util.Lazy.get(Lazy.java:114) ~[spring-data-commons-2.6.1.jar:2.6.1] at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:328) ~[spring-data-commons-2.6.1.jar:2.6.1] at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:144) ~[spring-data-jpa-2.6.1.jar:2.6.1] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863) ~[spring-beans-5.3.15.jar:5.3.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.3.15.jar:5.3.15] ... 49 common frames omitted Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List promisor.promisor.domain.team.dao.TeamRepository.findGroupInfoWithMembers(java.lang.Long)! at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:96) ~[spring-data-jpa-2.6.1.jar:2.6.1] at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:66) ~[spring-data-jpa-2.6.1.jar:2.6.1] at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:51) ~[spring-data-jpa-2.6.1.jar:2.6.1] at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:163) ~[spring-data-jpa-2.6.1.jar:2.6.1] at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:252) ~[spring-data-jpa-2.6.1.jar:2.6.1] at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:87) ~[spring-data-jpa-2.6.1.jar:2.6.1] at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.lookupQuery(QueryExecutorMethodInterceptor.java:102) ~[spring-data-commons-2.6.1.jar:2.6.1] ... 71 common frames omitted Caused by: java.lang.NullPointerException: Cannot invoke "org.hibernate.hql.internal.ast.tree.FromElement.setAllPropertyFetch(boolean)" because "fromElement" is null at org.hibernate.hql.internal.ast.HqlSqlWalker.createFromJoinElement(HqlSqlWalker.java:431) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.joinElement(HqlSqlBaseWalker.java:3990) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElement(HqlSqlBaseWalker.java:3776) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromElementList(HqlSqlBaseWalker.java:3654) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.fromClause(HqlSqlBaseWalker.java:737) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:593) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:330) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:278) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:276) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:192) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:636) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:748) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:114) ~[hibernate-core-5.6.4.Final.jar:5.6.4.Final] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na] at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:362) ~[spring-orm-5.3.15.jar:5.3.15] at com.sun.proxy.$Proxy139.createQuery(Unknown Source) ~[na:na] at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:90) ~[spring-data-jpa-2.6.1.jar:2.6.1] ... 77 common frames omitted
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
JPA 엔티티 단건 조회 시 하위 테이블 값이 null 들어가는 문제 해결 방법 문의 건
JPA 엔티티 단건 조회 시 하위 테이블 값이 null 들어가는 문제 해결 방법 문의 건 안녕하세요~ 강사님 수업 잘 듣고 있습니다 회사에서 JPA 를 도입해서 사용중인데요 연관관계 테이블이가 많은 오더단건 정보(헤더와 연관된 하위테이블 모두) 를 가져와 엔티티를 조회후에 맵스트럭처를 통해 JSON으로 외부로 데이터 전송하는 부분을 구현중입니다 리파지토리 extends JpaRepository 를 사용해서 리파지토리.getOne 을 통해서 엔티를 꺼내왔는데 이상하게도 브레이크포인트 디버깅을 걸어서 확인해보면 맵스트럭쳐를 통해 JSON 을 변경하기전 엔티티에 담겨있는 오더단건 정보(헤더와 연관된 하위테이블 모두)가 잘 담겨있을줄 알았지만, 헤더테이블 엔티티 Header Table A 만 데이터가 담겨있고, 연관된하위테이블 엔티티는 모두 null 로 들로가있습니다 이부분을 어떻게 해결해야 하는지 도움 부탁드립니다 (관련 블로그나, 참고 URL 블로그등을 알려주시면 참고하겠습니다) █ Header Table A ██ Detail Table A_1 @ManyToOne(fetch = FetchType.LAZY) private List<> ███ Detail Table A_1_1 @ManyToOne(fetch = FetchType.LAZY) private List<> ███ Detail Table A_1_2 @ManyToOne(fetch = FetchType.LAZY) private List<> ████ Detail Table A_1_2_1 ██ Detail Table B_1 @ManyToOne(fetch = FetchType.LAZY) private List<> ██ Detail Table C_1 @ManyToOne(fetch = FetchType.LAZY) private List<> ██ Detail Table D_1 @ManyToOne(fetch = FetchType.LAZY) private List<> ██ Detail Table E_1 @ManyToOne(fetch = FetchType.LAZY) private List<> 김동희 드림