월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
16:10 페이징 쿼리, mvc 관련 질문드립니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.안녕하세요 영한님 jpa 강의 정말 재미있게 잘 듣고 있습니다. 이번에 페이징 한계돌파 강의를 들으면서 실습을 하던 중 16:10쯤에 저의 개발환경에서 발생한 쿼리가 영한님의 개발환경에서 발생한 쿼리와 다른 것 같아서 질문드립니다. where __row__ >= 2 and __row__ < 102; 쿼리로 페이징이 적용되어 결과는 원하는 대로 나왔지만, 예상과는 조금 다르게 아래와 같은 서브 쿼리가 나갔습니다. 데이터베이스 방언 문제는 아닌 것 같고 jpa 버전 문제일까요? 2022-05-04 01:14:49.015 DEBUG 21484 --- [nio-8081-exec-6] org.hibernate.SQL : with query as (select inner_query.*, row_number() over ( order by current_timestamp) as __row__ from ( select order0_.order_id as order_id1_6_0_, member1_.member_id as member_i1_4_1_, delivery2_.delivery_id as delivery1_2_2_, order0_.delivery_id as delivery4_6_0_, order0_.member_id as member_i5_6_0_, order0_.order_date as order_da2_6_0_, order0_.order_status as order_st3_6_0_, member1_.city as city2_4_1_, member1_.street as street3_4_1_, member1_.zip_code as zip_code4_4_1_, member1_.name as name5_4_1_, delivery2_.city as city2_2_2_, delivery2_.street as street3_2_2_, delivery2_.zip_code as zip_code4_2_2_, delivery2_.status as status5_2_2_ from orders order0_ inner join member member1_ on order0_.member_id=member1_.member_id inner join delivery delivery2_ on order0_.delivery_id=delivery2_.delivery_id ) inner_query ) select order_id1_6_0_, member_i1_4_1_, delivery1_2_2_, delivery4_6_0_, member_i5_6_0_, order_da2_6_0_, order_st3_6_0_, city2_4_1_, street3_4_1_, zip_code4_4_1_, name5_4_1_, city2_2_2_, street3_2_2_, zip_code4_2_2_, status5_2_2_ from query where __row__ >= ? and __row__ < ? 2022-05-04 01:14:49.035 INFO 21484 --- [nio-8081-exec-6] p6spy : #1651594489035 | took 3ms | statement | connection 8| url jdbc:h2:tcp://localhost/~/jpashopping with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( select order0_.order_id as order_id1_6_0_, member1_.member_id as member_i1_4_1_, delivery2_.delivery_id as delivery1_2_2_, order0_.delivery_id as delivery4_6_0_, order0_.member_id as member_i5_6_0_, order0_.order_date as order_da2_6_0_, order0_.order_status as order_st3_6_0_, member1_.city as city2_4_1_, member1_.street as street3_4_1_, member1_.zip_code as zip_code4_4_1_, member1_.name as name5_4_1_, delivery2_.city as city2_2_2_, delivery2_.street as street3_2_2_, delivery2_.zip_code as zip_code4_2_2_, delivery2_.status as status5_2_2_ from orders order0_ inner join member member1_ on order0_.member_id=member1_.member_id inner join delivery delivery2_ on order0_.delivery_id=delivery2_.delivery_id ) inner_query ) select order_id1_6_0_, member_i1_4_1_, delivery1_2_2_, delivery4_6_0_, member_i5_6_0_, order_da2_6_0_, order_st3_6_0_, city2_4_1_, street3_4_1_, zip_code4_4_1_, name5_4_1_, city2_2_2_, street3_2_2_, zip_code4_2_2_, status5_2_2_ from query where __row__ >= ? and __row__ < ? with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( select order0_.order_id as order_id1_6_0_, member1_.member_id as member_i1_4_1_, delivery2_.delivery_id as delivery1_2_2_, order0_.delivery_id as delivery4_6_0_, order0_.member_id as member_i5_6_0_, order0_.order_date as order_da2_6_0_, order0_.order_status as order_st3_6_0_, member1_.city as city2_4_1_, member1_.street as street3_4_1_, member1_.zip_code as zip_code4_4_1_, member1_.name as name5_4_1_, delivery2_.city as city2_2_2_, delivery2_.street as street3_2_2_, delivery2_.zip_code as zip_code4_2_2_, delivery2_.status as status5_2_2_ from orders order0_ inner join member member1_ on order0_.member_id=member1_.member_id inner join delivery delivery2_ on order0_.delivery_id=delivery2_.delivery_id ) inner_query ) select order_id1_6_0_, member_i1_4_1_, delivery1_2_2_, delivery4_6_0_, member_i5_6_0_, order_da2_6_0_, order_st3_6_0_, city2_4_1_, street3_4_1_, zip_code4_4_1_, name5_4_1_, city2_2_2_, street3_2_2_, zip_code4_2_2_, status5_2_2_ from query where __row__ >= 2 and __row__ < 102; 2022-05-04 01:14:49.038 DEBUG 21484 --- [nio-8081-exec-6] org.hibernate.SQL : select orderitems0_.order_id as order_id5_5_0_, orderitems0_.order_item_id as order_it1_5_0_, orderitems0_.order_item_id as order_it1_5_1_, orderitems0_.count as count2_5_1_, orderitems0_.item_id as item_id4_5_1_, orderitems0_.order_id as order_id5_5_1_, orderitems0_.order_price as order_pr3_5_1_ from order_item orderitems0_ where orderitems0_.order_id=? 2022-05-04 01:14:49.040 INFO 21484 --- [nio-8081-exec-6] p6spy : #1651594489040 | took 0ms | statement | connection 8| url jdbc:h2:tcp://localhost/~/jpashopping select orderitems0_.order_id as order_id5_5_0_, orderitems0_.order_item_id as order_it1_5_0_, orderitems0_.order_item_id as order_it1_5_1_, orderitems0_.count as count2_5_1_, orderitems0_.item_id as item_id4_5_1_, orderitems0_.order_id as order_id5_5_1_, orderitems0_.order_price as order_pr3_5_1_ from order_item orderitems0_ where orderitems0_.order_id=? select orderitems0_.order_id as order_id5_5_0_, orderitems0_.order_item_id as order_it1_5_0_, orderitems0_.order_item_id as order_it1_5_1_, orderitems0_.count as count2_5_1_, orderitems0_.item_id as item_id4_5_1_, orderitems0_.order_id as order_id5_5_1_, orderitems0_.order_price as order_pr3_5_1_ from order_item orderitems0_ where orderitems0_.order_id=11; 2022-05-04 01:14:49.044 DEBUG 21484 --- [nio-8081-exec-6] org.hibernate.SQL : select item0_.item_id as item_id2_3_0_, item0_.name as name3_3_0_, item0_.price as price4_3_0_, item0_.stock_quantity as stock_qu5_3_0_, item0_.artist as artist6_3_0_, item0_.etc as etc7_3_0_, item0_.author as author8_3_0_, item0_.isbn as isbn9_3_0_, item0_.actor as actor10_3_0_, item0_.director as directo11_3_0_, item0_.dtype as dtype1_3_0_ from item item0_ where item0_.item_id=? 2022-05-04 01:14:49.046 INFO 21484 --- [nio-8081-exec-6] p6spy : #1651594489046 | took 0ms | statement | connection 8| url jdbc:h2:tcp://localhost/~/jpashopping select item0_.item_id as item_id2_3_0_, item0_.name as name3_3_0_, item0_.price as price4_3_0_, item0_.stock_quantity as stock_qu5_3_0_, item0_.artist as artist6_3_0_, item0_.etc as etc7_3_0_, item0_.author as author8_3_0_, item0_.isbn as isbn9_3_0_, item0_.actor as actor10_3_0_, item0_.director as directo11_3_0_, item0_.dtype as dtype1_3_0_ from item item0_ where item0_.item_id=? select item0_.item_id as item_id2_3_0_, item0_.name as name3_3_0_, item0_.price as price4_3_0_, item0_.stock_quantity as stock_qu5_3_0_, item0_.artist as artist6_3_0_, item0_.etc as etc7_3_0_, item0_.author as author8_3_0_, item0_.isbn as isbn9_3_0_, item0_.actor as actor10_3_0_, item0_.director as directo11_3_0_, item0_.dtype as dtype1_3_0_ from item item0_ where item0_.item_id=9; 2022-05-04 01:14:49.048 DEBUG 21484 --- [nio-8081-exec-6] org.hibernate.SQL : select item0_.item_id as item_id2_3_0_, item0_.name as name3_3_0_, item0_.price as price4_3_0_, item0_.stock_quantity as stock_qu5_3_0_, item0_.artist as artist6_3_0_, item0_.etc as etc7_3_0_, item0_.author as author8_3_0_, item0_.isbn as isbn9_3_0_, item0_.actor as actor10_3_0_, item0_.director as directo11_3_0_, item0_.dtype as dtype1_3_0_ from item item0_ where item0_.item_id=? 2022-05-04 01:14:49.050 INFO 21484 --- [nio-8081-exec-6] p6spy : #1651594489050 | took 0ms | statement | connection 8| url jdbc:h2:tcp://localhost/~/jpashopping select item0_.item_id as item_id2_3_0_, item0_.name as name3_3_0_, item0_.price as price4_3_0_, item0_.stock_quantity as stock_qu5_3_0_, item0_.artist as artist6_3_0_, item0_.etc as etc7_3_0_, item0_.author as author8_3_0_, item0_.isbn as isbn9_3_0_, item0_.actor as actor10_3_0_, item0_.director as directo11_3_0_, item0_.dtype as dtype1_3_0_ from item item0_ where item0_.item_id=? select item0_.item_id as item_id2_3_0_, item0_.name as name3_3_0_, item0_.price as price4_3_0_, item0_.stock_quantity as stock_qu5_3_0_, item0_.artist as artist6_3_0_, item0_.etc as etc7_3_0_, item0_.author as author8_3_0_, item0_.isbn as isbn9_3_0_, item0_.actor as actor10_3_0_, item0_.director as directo11_3_0_, item0_.dtype as dtype1_3_0_ from item item0_ where item0_.item_id=10; 또한 api가 아닌 mvc 패턴으로 컬렉션을 find할 때에는 dto가 아닌 엔티티를 그대로 repository에서 찾아서 view 화면에 넘기는데, 이 때는 쿼리 성능 최적화를 어떻게 할 수 있을까요? (타임리프로 order, orderItem의 결과를 보여준다고 가정할 때)
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
v1에서 v2로 바꿀때 postman이 동작하질 않습니다
안녕하세요 v1에서 v2로 바꿀때 postman이 동작하질 않습니다 엔티티를 조금 제 입맛에 맞게 변경했는데 v1은 도작하나 v2는 동작하질 않아서.. 이게 왜 이런 오류가 나는지 모르겠습니다 [MemberApiController] package mkyu.loginApi.domain.api; import com.fasterxml.jackson.databind.annotation.JsonValueInstantiator; import lombok.Data; import lombok.RequiredArgsConstructor; import lombok.Value; import mkyu.loginApi.domain.member.Member; import mkyu.loginApi.domain.service.MemberService; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; @RestController @RequiredArgsConstructor public class MemberApiController { private final MemberService memberService; //RequestBody는 json의 데이터를 Member로 다 넣어줌, 엔티티를 파라미터로 넣으면 안됨/ 수정, sns로그인 때문에 1:1이 안되서 오류남 @PostMapping("/api/v1/members") public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member) { Long idx = memberService.join(member); return new CreateMemberResponse(idx); } @PostMapping("/api/v2/members") public CreateMemberResponse saveMemberV2(@RequestBody @Valid CreateMemberRequest request) { Member member = new Member(); member.setName(request.getName()); Long idx = memberService.join(member); System.out.println(idx); return new CreateMemberResponse(idx); } // @Data static class CreateMemberRequest { private String name; } @Data static class CreateMemberResponse { private Long idx; public CreateMemberResponse(Long idx) { this.idx = idx; } } } [Member] package mkyu.loginApi.domain.member; import lombok.*; import mkyu.loginApi.domain.BaseTimeEntity; import javax.persistence.*; import javax.validation.constraints.NotEmpty; @Table(name = "MEMBER") @Getter @Setter @NoArgsConstructor @Entity @AllArgsConstructor @Builder public class Member extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "member_idx") private Long idx; //primary Key // @NotEmpty @Column(nullable = false, length = 30, unique = true) private String id;//아이디 // @NotEmpty private String password;//비밀번호 // @NotEmpty @Column(nullable = false, length = 30) private String name;//이름(실명) // @NotEmpty @Column(nullable = false, length = 30) private String mobile;//번호 // @NotEmpty @Column(nullable = false, length = 30) private String email;//이메일 @Column(length = 1000) private String refreshToken;//RefreshToken public Member(String password) { this.password = password; } public Member(String id, String password, String name, String mobile, String email) { this.id = id; this.password = password; this.name = name; this.mobile = mobile; this.email = email; } } [오류메시지] 2022-05-02 11:03:02.010 DEBUG 45809 --- [nio-8095-exec-1] o.s.web.servlet.DispatcherServlet : POST "/api/v2/members", parameters={} 2022-05-02 11:03:02.013 DEBUG 45809 --- [nio-8095-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to mkyu.loginApi.domain.api.MemberApiController#saveMemberV2(CreateMemberRequest) 2022-05-02 11:03:02.014 DEBUG 45809 --- [nio-8095-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor 2022-05-02 11:03:02.018 DEBUG 45809 --- [nio-8095-exec-1] m.m.a.RequestResponseBodyMethodProcessor : Read "application/json;charset=UTF-8" to [MemberApiController.CreateMemberRequest(name=l2e)] 2022-05-02 11:03:02.019 DEBUG 45809 --- [nio-8095-exec-1] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(565980721<open>)] for JPA transaction 2022-05-02 11:03:02.020 DEBUG 45809 --- [nio-8095-exec-1] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [mkyu.loginApi.domain.service.MemberService.join]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT 2022-05-02 11:03:02.033 DEBUG 45809 --- [nio-8095-exec-1] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@211015b3] 2022-05-02 11:03:02.036 INFO 45809 --- [nio-8095-exec-1] p6spy : #1651456982036 | took 0ms | statement | connection 13| url jdbc:h2:tcp://localhost/~/test select member0_.member_idx as member_i1_0_, member0_.created_date as created_2_0_, member0_.email as email3_0_, member0_.id as id4_0_, member0_.mobile as mobile5_0_, member0_.name as name6_0_, member0_.password as password7_0_, member0_.refresh_token as refresh_8_0_ from member member0_ where member0_.name=? select member0_.member_idx as member_i1_0_, member0_.created_date as created_2_0_, member0_.email as email3_0_, member0_.id as id4_0_, member0_.mobile as mobile5_0_, member0_.name as name6_0_, member0_.password as password7_0_, member0_.refresh_token as refresh_8_0_ from member member0_ where member0_.name='l2e'; 2022-05-02 11:03:02.041 INFO 45809 --- [nio-8095-exec-1] p6spy : #1651456982041 | took 1ms | statement | connection 13| url jdbc:h2:tcp://localhost/~/test insert into member (member_idx, created_date, email, id, mobile, name, password, refresh_token) values (default, ?, ?, ?, ?, ?, ?, ?) insert into member (member_idx, created_date, email, id, mobile, name, password, refresh_token) values (default, NULL, NULL, NULL, NULL, 'l2e', NULL, NULL); 2022-05-02 11:03:02.041 WARN 45809 --- [nio-8095-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23502, SQLState: 23502 2022-05-02 11:03:02.041 ERROR 45809 --- [nio-8095-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : NULL not allowed for column "EMAIL"; SQL statement: insert into member (member_idx, created_date, email, id, mobile, name, password, refresh_token) values (default, ?, ?, ?, ?, ?, ?, ?) [23502-200] 2022-05-02 11:03:02.042 DEBUG 45809 --- [nio-8095-exec-1] o.s.orm.jpa.JpaTransactionManager : Initiating transaction rollback 2022-05-02 11:03:02.042 DEBUG 45809 --- [nio-8095-exec-1] o.s.orm.jpa.JpaTransactionManager : Rolling back JPA transaction on EntityManager [SessionImpl(565980721<open>)] 2022-05-02 11:03:02.042 INFO 45809 --- [nio-8095-exec-1] p6spy : #1651456982042 | took 0ms | rollback | connection 13| url jdbc:h2:tcp://localhost/~/test ; 2022-05-02 11:03:02.043 DEBUG 45809 --- [nio-8095-exec-1] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction 2022-05-02 11:03:02.043 DEBUG 45809 --- [nio-8095-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor 2022-05-02 11:03:02.043 DEBUG 45809 --- [nio-8095-exec-1] o.s.web.servlet.DispatcherServlet : Failed to complete request: org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement 2022-05-02 11:03:02.050 ERROR 45809 --- [nio-8095-exec-1] 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.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column "EMAIL"; SQL statement: insert into member (member_idx, created_date, email, id, mobile, name, password, refresh_token) values (default, ?, ?, ?, ?, ?, ?, ?) [23502-200] at org.h2.message.DbException.getJdbcSQLException(DbException.java:459) ~[h2-1.4.200.jar:1.4.200] at org.h2.engine.SessionRemote.done(SessionRemote.java:611) ~[h2-1.4.200.jar:1.4.200] at org.h2.command.CommandRemote.executeUpdate(CommandRemote.java:237) ~[h2-1.4.200.jar:1.4.200] at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:191) ~[h2-1.4.200.jar:1.4.200] at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:152) ~[h2-1.4.200.jar:1.4.200] at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61) ~[HikariCP-4.0.3.jar:na] at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java) ~[HikariCP-4.0.3.jar:na] at com.p6spy.engine.wrapper.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:94) ~[p6spy-3.9.0.jar:na] at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.dialect.identity.GetGeneratedKeysDelegate.executeAndExtract(GetGeneratedKeysDelegate.java:58) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:43) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3279) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3885) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:84) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:645) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:282) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:263) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:330) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:287) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:123) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:185) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:128) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:55) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:756) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:742) ~[hibernate-core-5.6.8.Final.jar:5.6.8.Final] at jdk.internal.reflect.GeneratedMethodAccessor44.invoke(Unknown Source) ~[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:567) ~[na:na] at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:362) ~[spring-orm-5.3.19.jar:5.3.19] at jdk.proxy2/jdk.proxy2.$Proxy100.persist(Unknown Source) ~[na:na] at jdk.internal.reflect.GeneratedMethodAccessor44.invoke(Unknown Source) ~[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:567) ~[na:na] at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311) ~[spring-orm-5.3.19.jar:5.3.19] at jdk.proxy2/jdk.proxy2.$Proxy100.persist(Unknown Source) ~[na:na] at mkyu.loginApi.domain.repository.MemberRepository.save(MemberRepository.java:17) ~[classes/:na] at mkyu.loginApi.domain.repository.MemberRepository$$FastClassBySpringCGLIB$$cfc41407.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 mkyu.loginApi.domain.repository.MemberRepository$$EnhancerBySpringCGLIB$$e8dc9246.save(<generated>) ~[classes/:na] at mkyu.loginApi.domain.service.MemberService.join(MemberService.java:24) ~[classes/:na] at mkyu.loginApi.domain.service.MemberService$$FastClassBySpringCGLIB$$316efea1.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.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.19.jar:5.3.19] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.19.jar:5.3.19] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[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 mkyu.loginApi.domain.service.MemberService$$EnhancerBySpringCGLIB$$b1b444be.join(<generated>) ~[classes/:na] at mkyu.loginApi.domain.api.MemberApiController.saveMemberV2(MemberApiController.java:34) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) ~[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:567) ~[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.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.19.jar:5.3.19] at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[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:831) ~[na:na] 2022-05-02 11:03:02.052 DEBUG 45809 --- [nio-8095-exec-1] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for POST "/error", parameters={} 2022-05-02 11:03:02.053 DEBUG 45809 --- [nio-8095-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest) 2022-05-02 11:03:02.053 DEBUG 45809 --- [nio-8095-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor 2022-05-02 11:03:02.054 DEBUG 45809 --- [nio-8095-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json] 2022-05-02 11:03:02.055 DEBUG 45809 --- [nio-8095-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [{timestamp=Mon May 02 11:03:02 KST 2022, status=500, error=Internal Server Error, path=/api/v2/membe (truncated)...] 2022-05-02 11:03:02.055 DEBUG 45809 --- [nio-8095-exec-1] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor 2022-05-02 11:03:02.056 DEBUG 45809 --- [nio-8095-exec-1] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 500 감사합니다!!
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
12분6초 : 쿼리 수 계산 질문입니다.
List<Order> orders = orderRepository.findAllWithMemberDelivery();List<OrderDto> result = orders.stream() .map(o-> new OrderDto(o)) .collect(Collectors.toList()); 처음 orders 생성하는데 쿼리 한번 제외하고,result 생성하는데 쿼리 OrderItem 2개 ,그중 OrderItem 당 Item 2개라서 총 6번이라고 설명해주셨습니다. 근데 저는 OrderItem 엔티티에서 @ManyToOne(fetch = LAZY)@JoinColumn(name = "item_id")private Item item; 으로 Item필드가 다대일로 되어있는데 OrderItem 하나 불러올때 Item도 하나 불러오는게 당연하다고 생각하는데 왜 Item을 두개나 불러오는지 모르겠습니다. 그래서 6번 쿼리가 아니라 4번이라고 생각하됩니다 ㅠㅠ 어디에서 잘못이해한걸까요
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
criteria 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 안녕하세요 criteria에 대해서 궁금한게 있어서 질문드립니다. criteria를 사용해서 fetch join시 em.createQuery에서 사용했던 " join fetch o.orderItmes oi" + " join fetch oi.item i" 이 부분 처럼 객체 그래프 탐색으로 orderItem과 item을 조인 할 수 있는 방법 을 알 수 있을까요?저 부분을 해결을 못 해서 orderItems까지만 패치 조인이 적용 돼고 item은 패치 조인을 적용하지 못 해서 1 + N현상이 발생하는데 해결하고 싶습니다 ㅠㅠ
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
java11에서 compileQuerydsl태스크가 계속 실패중인데요
원래 강의 소스 보면 build.gradle에서 sourceCompatibility = '11'이었는데 이번 강의에서 sourceCompatibility = '1.8' 로 바껴있는것 같더군요 혹시 일부러 바꾸신건지? 그냥 sourceCompatibility = '11'로 해서 gradle돌려보니 자꾸 compileQuerydsl에서 실패하는 것 같습니다 java11에서 사용할 수 있는 방법 있을까요?(강의 소스를 좀 커스터마이징 한 부분이 있어서 java8로 돌리고 실행하니 서버가 뻗어버리는지라 그냥 11에서 실행하고싶어요) 정말로 java11이라서 gradle에러나는건지 좀 의문스럽긴 합니다만 (개발환경에 다운로드된 querydsl버전은 5.0.0최신버전인것 같습니다) PS. 혹시 스프링부트 버전과도 상관이 있는건지 잘 모르겠네요. 지금 쓰고있는건 2.6.6버전이거든요(강의시점에서 꽤나 시간이 지난것도 있고해서 최신버전으로 쓰고있긴한데)
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
querydsl 의존관계 없는 left join 문의
안녕하세요! 실무에서 jpa를 쓰게 되서 강사님의 책과 강의를 번갈아 보면서 열심히 개발하던 중에 궁금한 점이 있어 문의드립니다. 쓰다보니 query dsl이 참 편하더라구요! 그런데 연관관계 없는 두 개 entity를 조인해서 데이터를 조회해오고 싶은데, 아래와 같이 쿼리를 작성하니 실행 중에 QuerySyntaxException이 발생합니다. List<HistoryDto> historyList = queryFactory .select(Projections.fields(HistoryDto.class, pmntHistoryEntity.approvalNo, pmntHistoryEntity.approvalDate, pmntHistoryEntity.cancelType, pmntHistoryEntity.trxId, pmntHistoryEntity.trxReqDate, creditCardEntity.cardName, creditCardEntity.cardNumber )) .from(pmntHistoryEntity) .leftJoin(creditCardEntity).on(pmntHistoryEntity.cardToken.eq(creditCardEntity.cardToken)) .where( eqUserId(dto.getUserId()), eqOrderId(dto.getOrderId()) ) .fetch(); exception = QuerySyntaxException: begin 0, end -1, length 19 queryDsl에서 연관 관계 없어도 on 절을 통해 join이 가능한 것으로 알고 있는데 projection과 호환이 안되는 걸까요? 하루종일 구글링을 해도 나오질 않네요.. 혹시 알고 계시다면 답변 부탁드립니다 ㅠ_ㅠ
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
GET /api/v2/orders 조회 관련 질문
@GetMapping("/api/v2/orders") public List<OrderDto> ordersV2() { List<Order> orders = orderRepository.findAllByString(new OrderSearch()); List<OrderDto> result = orders.stream() .map( o -> new OrderDto(o) ) .collect(Collectors.toList()); return result; } @Data static class OrderDto { private Long orderId; private String name; private LocalDateTime orderDate; private OrderStatus orderStatus; private Address address; private List<OrderItem> orderItems; public OrderDto(Order order) { orderId = order.getId(); name = order.getMember().getName(); orderDate = order.getOrderDate(); orderStatus = order.getStatus(); address = order.getDelivery().getAddress(); order.getOrderItems().stream().forEach(o -> o.getItem().getId()); orderItems = order.getOrderItems(); } } 위 코드에서 OrderDto 생성자 함수 내에 getOrderItem 요소들을 순회시, 각 아이템을 get후에 getId를 호출 할 때 각 item 프록시들이 초기화 돼야 하는 것 아닌가요..? 강의에서는 getName을 통해 초기화 하길래, 위 코드처럼 getId로 하면 될까 궁금증이 생겨 실행해보니 orderItems 내에 item 이 null 값으로 나옵니다. getName 으로 초기화 할 때는 전부 다 들어있구요. 코드 구글 드라이브 링크: https://drive.google.com/drive/folders/17gdIodVzIPG8_XzTeYUVDbLdaScP6c2s
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
주문 조회 V4: JPA에서 DTO 직접 조회
안녕하세요. 궁금한게 생겨서 글을 남기게 되었습니다. 페치 조인은 관련된 엔티티들을 지연로딩하지 않고 쿼리 한번에 조회하는 것으로 알고있습니다. 해당하는 부분에서 패치조인으로 데이터를 가져온 후 for 루프를 돌면서 item을 업데이트하면 에러가 발생합니다. 왜 그런지 좀 알 수 있을까요? 페치 조인은 조회만 가능하고 수정은 불가능 한 건가요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
트랜잭션 범위 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 아래의 update 후 조회 로직에서 왜 select 쿼리가 나가지 않는가에 대한 질문 글들을 읽어보면, 강의의 업데이트 로직상 memberService의 update() 메서드에서 트랜잭션 범위가 넘어가면 기본적으로 영속성 컨텍스트의 내용은 모두 지워져서 이후 조회 로직에서 select가 나가야 맞지만, 추후에 배울 성능 최적화 기능 덕분에 update한 그 Member가 아직 1차캐시에 남아있게 되어 select 쿼리가 나가지 않는다고 이해하였습니다. 그렇다면 여기서 트랜잭션 범위를 넘어가면 영속성 컨텍스트가 비워진다 라고 설명해주셨는데, JPA 기본강의에서는 트랜잭션이 커밋된다고 해서 영속성 컨텍스트가 비워지지는 않는다 라고 설명해주셨습니다. Q1. 그러면 트랜잭션 범위를 넘어가기 전 커밋되는 경우에는 영.컨이 비워지지 않지만, 트랜잭션이 아예 끝나면 영.컨이 비워지는것이 맞을까요? (ex. 메소드 중간에 transaction.commit()을 호춣하거나, 혹은 JPQL 실행 직전에 커밋되는 경우) Q2. 여기서 트랜잭션의 범위가, 메소드 level에 적용되는 @Transactional 에 의해 , 그 메소드가 리턴되기까지를 말하는 것인지 or 아니면 @Transactional이 적용된 update() 메소드에서 컨트롤러로 실행이 옮겨갔기 떄문에 범위를 넘어섰다고 말하는 것인지, 트랜잭션의 범위 라는 개념과, 그 범위를 넘어섰다는 개념을 잘 모르겠습니다. (만약 전자라면, @Transactional이 붙은 메소드 단위로 트랜잭션 범위가 넘어가니, 메소드 호출될 때 마다 영.컨이 비워질 것 같습니다.)
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
distinct중복 제거에 대한질문입니다!!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]친근하면서 알짜 베기 강의 너무 잘보고있습니다 다름이아니라 저도 항상 생각했던 문제인데 user team onetomany manytoone 일때 team10개를 가져올때 user 는 1개만 가져오고 싶을때 jpa에서는 distinct를 붙히면 해결된다고 강의에서 봤는데요 썡 쿼리랑 다르게 jpa distinct는 중복을 엔티티로 제거해준다고 봤습니다 다만 이방법이 querydsl에서도 가능한 방법인지 궁금합니다 물론 곧 영한 님의 querydsl도 수강예정입니다 ex) jpaQueryFactory.select(qatable,qbtable).distinct().from(qatable).on(뭐시기)~~~ 이런 상황에서도 distinct가 jpa방식으로 작동하는지 질문드립니다 감사합니다
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
update후 다시 member를 조회할때 쿼리가 날라가지 않는이유
[질문 내용]update후 트랜젝션이 끝나면 그 후에 발생하는 memberService.findOne(id)에서는 새로운 트랜젝션에서 실행돼서 새롭게 select쿼리가 날아가야 한다고 생각했는데 실제 실행을 해보니까 update쿼리 이후에 다른 쿼리가 날아가지 않던데 이유가 궁금합니다!
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
DTO를 반환에서만 사용하면 안되나요?
다음과같이 컨트롤러로 받을때 DTO로 받고, Repository에서 엔티티로 다시 변환하는 모델을 생각하는데요 엔티티로 받아서 Repository 작업 후, Controller에 값을 넘겨줄 시기에 DTO로 변환해서 사용하는것은 설계가 잘못된 것인지 궁금합니다. 일종의 꼼수의 느낌이 나는데, 이렇게 사용하면 안되는지 질문 드립니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
컬렉션 페치 조인 질문이 있습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]여기에 질문 내용을 남겨주세요. 안녕하세요! 컬렉션 페치 조인 용어에서 간단한 질문이 있습니다. 컬렉션 조회 최적화 수업을 듣게 되면, OneToMany 관계에서 컬렉션 페치 조인을 하게 됩니다. 이때, 만약 '컬렉션 페치조인에서 컬렉션이 무엇이고 페치 조인이 무엇이에요?'라는 질문이 들어오면 먼저 findAllWithItem() 메서드를 예시로보면, (1) 페치 조인은 Order 테이블을 기준으로 member, delivery, orderItems, item 이 페치조인이 일어나고, (2) 컬렉션 orders 변수에 select문 결과를 저장 컬렉션 orders 변수에 select문 결과를 저장한다. 이와 같이 컬렉션와 페치조인이 사용되는 것을 컬렉션 페치조인이라고 한다. 라고 설명을 한다면 괜찮은 답안일까요? (나중에 면접에서 설명하라고 하셨을 때 이와 같이 하면 될지 고민이 많이되네요ㅠㅠ)
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
v3.1 쿼리 최적화
안녕하세요 선생님! v3.1에서 쿼리 실행 결과 order 조회-> orderItem 조회 -> item 이 조회됩니다. 저는 OrderItem 안에 item이 Lazy 로딩이니 페치 조인으로 가지고 오고 싶어서 다음과 같은 로직을 작성해보았습니다. @GetMapping("/api/v3.2/orders")public List<OrderDto> ordersV3_page2( @RequestParam(value = "offset", defaultValue = "0") int offset, @RequestParam(value = "limit", defaultValue = "100") int limit) { List<Order> orders = orderRepository.findWithMemberDelivery(offset, limit); List<Long> ids = orders.stream().map(order -> order.getId()).collect(toList()); List<OrderItem> orderItems = orderQueryRepository.findOrderDto(ids); return orders.stream() .map(order -> new OrderDto(order, orderItems)) .collect(toList());} public List<OrderItem> findOrderDto(List<Long> ids) { return em.createQuery( "select oi from OrderItem oi join fetch oi.item where oi.order.id in :ids", OrderItem.class) .setParameter("ids", ids) .getResultList();} public OrderDto(Order order, List<OrderItem> orderItems) { orderId = order.getId(); name = order.getMember().getName(); orderDate = order.getOrderDate(); orderStatus = order.getStatus(); address = order.getDelivery().getAddress(); this.orderItems = orderItems.stream().map(OrderItemDto::new).collect(toList());} 이와 같이 로직을 작성 하고 결과를 확인하니 위와 같이 모든 Item이 조회되었습니다. 혹시 fetch join 이 문제 일까 싶어서 fetch join 을 제외하고 실행하더라도 동일한 결과가 나왔습니다. fetch join을 빼고 실행하면 강의에서 나온 것과 동일하게 쿼리가 실행되지만 결과값은 다른 것을 확인했습니다. -> batch_fetch_size를 사용했을때만 동일한 쿼리가 실행됨.(결과값은 다름) batch_fetch_size 사용 시 단순히 in 쿼리로 결과를 가져오는 것이 아니라 지연로딩을 생각해서 결과값을 가져온다고 생각하면 되는걸까요? 동일한 쿼리가 실행되는데도 결과 값이 다르게 나오는게 이해가 잘안됩니다 ㅠㅠ
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
조회가 궁금합니다.
안녕하세요 궁금한 것이 생겨 글을 올리게 되었습니다. 저희가 코드를 작성해서 서버에 올렸다는 가정하에 서버는 종료되지 않고 계속 실행 중일 때, 클라이언트1이 어떤 것을 조회하면 해당 api를 타고 메서드 내부에 컬렉션을 사용해서 클라이언트 1에게 결과값을 반환하는데 클라이언트 1이 다시 같은 것을 요청하면 똑같이 동작해서 반환할 경우, 지난 요청에 의해 저장해놓은 데이터가 있다면 새롭게 요청할 때마다 데이터는 계속 쌓이게 되는 것인가요?? 메모리관리가 어떻게 되는 것인지 너무 궁금해서 올리게 되었습니다. 친한 지인에게 물어보니 약한 참조를 하거나 new 연산을 할 경우 가바지에 의해 메모리 관리가 된다고 말해주었는데 혹시 실무에서는 어떤 식으로 하는지 조언 부탁드립니다. 항상 좋은 강의 올려주셔서 정말 감사합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Result class와 주문 조회에 대해 궁금증이 생겨 질문드립니다.
항상 친절하게 답변 주셔서 감사합니다 "회원조회 API" 강의에서 바로 Array로 반환을 하면 스펙이 굳어져 유연성이 떨어지기 때문에 임의의 Result class를 생성해 반환내용을 Result에 담아 반환하였는데, 주문 조회 시에는 이와 같은 방법으로 json을 반환할 필요가 없기 때문에 강의에서 다루지 않으신건지 궁금합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
stream이 아닌 querydsl transform을 이용하는 방법에대한 문의
안녕하세요 8:30초대 강의를 보면 1:N관계의 list형태를 mapping하기 위해 flats .stream ~ .collect ~ 형태를 이용하고 있는데요 실무에서도 비슷한 사례가있어, 처음에 강사님처럼 어플리케이션단에 코드를 짰다가, 코드가 너무 복잡해져서 QueryDsl에서 transform + GroupBy.list를 이용하는식으로 변경해봤는데요. (아래 예시참조) from(Entity) // 1:N 관계의 List<Object> 를 추출, key : Entity.Id .transform( groupBy(Entity.Id) .list( Projections.fields(Example.class, Entity.Id, list( Projections.fields(Detail.class, Detail.id Detail.name ) ).as("DetailList") ) ) ) 문제는 구글링을 해보니, 해당 방식이 쿼리결과를 memory에서 리스트형태로 만들어내는것이라고 하더라구요. 예전에 강사님의 강의에서 '컬렉션 fetch join은 페이징을 이용할 수 없다'는 내용을 설명해주실 때, 해당 동작이 메모리에서 일어나기때문에 OOM이 발생할 수 있다 라고 말씀해주셨는데 이와 마찬가지로 transform , Groupby.list를 이용하는 것 역시 문제가 발생할까봐 우려스럽네요 아래 두가지 질문에 답변 부탁드립니다. Q1) 강사님의 application단에서 짜는 방식이 나을지 아니면 querydsl단에서 transform & Groupby.list를 이용하는게 나을지 고민되는데 두가지 방법중 무엇을 선택하는게 좋을까요? 후자의 경우 OOM이 발생하지는 않을지도 궁금합니다.. Q2) memory에서 작업하는게 위험한 이유가 뭔가요? 강사님처럼 application단에서 로직을 수행하는것도 memory에서 동작하는것 아닌가요? 친절하고 유익한 강의 늘 감사드립니다. 답변 부탁드립니다!
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
커멘드와 쿼리 분리에 대해
안녕하세요 항상 강의 잘 듣고 있습니다! 제가 이해력이 부족하여 모든 질문을 보았음에도 이해가 가지않아 질문 합니다! ㅜ 현재 강의의 예시에는 -------- orderV3 컨트롤러 -> 읽기전용 @Transactional이 설정된 OrderQueryService -> OrderRepository 이렇게 호출이 되어 있는데요 -------- 이 예시는 핵심 비즈니스 로직 없이 OrderQueryService 즉 화면이나 API에 맞춘 서비스만 있는 예시인건가요 ? 아니면 Repository 호출을 OrderService가 있다고 치고 OrderQueryService안에 OrderService(핵심비즈니스로직)이 있고 그안에 OrderRepository를 호출 했다고 치는건가요 ? -------- (예를들면 이렇게 ) orderV3 컨트롤러 -> OrderQueryService -> OrderService(생략) -> OrderRepository -------- 결론은 OrderService와 OrderQueryService가 같이 어떻게 쓰여지는지 이해가 가질 않습니다..
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
주문내역을 들어갈 때 에러가 났습니다.
QueryDSL 마지막 강의를 듣고 주문내역을 들어가는 부분에서 에러가 났습니다. 아래와 같이 에러가 났습니다. https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-API%EA%B0%9C%EB%B0%9C-%EC%84%B1%EB%8A%A5%EC%B5%9C%EC%A0%81%ED%99%94/lecture/24342?tab=community&volume=0.70&quality=1080&speed=1.25&q=486752 이 부분을 참고하였는데 해결을 못하였습니다... Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Thu Apr 14 00:00:05 KST 2022 There was an unexpected error (type=Internal Server Error, status=500). An error happened during template parsing (template: "class path resource [templates/order/orderList.html]") org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/order/orderList.html]") at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:241) at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parseStandalone(AbstractMarkupTemplateParser.java:100) at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:666) at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098) at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072) at org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:366) at org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:190) at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1401) at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1145) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1084) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:829) Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "item.member.name" (template: "order/orderList" - line 34, col 21) at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393) at org.attoparser.MarkupParser.parse(MarkupParser.java:257) at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230) ... 48 more Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "item.member.name" (template: "order/orderList" - line 34, col 21) at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:292) at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166) at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66) at org.thymeleaf.standard.expression.Expression.execute(Expression.java:109) at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138) at org.thymeleaf.standard.processor.AbstractStandardExpressionAttributeTagProcessor.doProcess(AbstractStandardExpressionAttributeTagProcessor.java:144) at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74) at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633) at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314) at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205) at org.thymeleaf.engine.Model.process(Model.java:282) at org.thymeleaf.engine.Model.process(Model.java:290) at org.thymeleaf.engine.IteratedGatheringModelProcessable.processIterationModel(IteratedGatheringModelProcessable.java:367) at org.thymeleaf.engine.IteratedGatheringModelProcessable.process(IteratedGatheringModelProcessable.java:221) at org.thymeleaf.engine.ProcessorTemplateHandler.handleCloseElement(ProcessorTemplateHandler.java:1640) at org.thymeleaf.engine.TemplateHandlerAdapterMarkupHandler.handleCloseElementEnd(TemplateHandlerAdapterMarkupHandler.java:388) at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler$InlineMarkupAdapterPreProcessorHandler.handleCloseElementEnd(InlinedOutputExpressionMarkupHandler.java:322) at org.thymeleaf.standard.inline.OutputExpressionInlinePreProcessorHandler.handleCloseElementEnd(OutputExpressionInlinePreProcessorHandler.java:220) at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler.handleCloseElementEnd(InlinedOutputExpressionMarkupHandler.java:164) at org.attoparser.HtmlElement.handleCloseElementEnd(HtmlElement.java:169) at org.attoparser.HtmlMarkupHandler.handleCloseElementEnd(HtmlMarkupHandler.java:412) at org.attoparser.MarkupEventProcessorHandler.handleCloseElementEnd(MarkupEventProcessorHandler.java:473) at org.attoparser.ParsingElementMarkupUtil.parseCloseElement(ParsingElementMarkupUtil.java:201) at org.attoparser.MarkupParser.parseBuffer(MarkupParser.java:725) at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:301) ... 50 more Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1021E: A problem occurred whilst attempting to access the property 'name': 'Unable to access property 'name' through getter method' at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:209) at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104) at org.springframework.expression.spel.ast.PropertyOrFieldReference.access$000(PropertyOrFieldReference.java:51) at org.springframework.expression.spel.ast.PropertyOrFieldReference$AccessorLValue.getValue(PropertyOrFieldReference.java:406) at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:92) at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:112) at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:338) at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:265) ... 75 more Caused by: org.springframework.expression.AccessException: Unable to access property 'name' through getter method at org.springframework.expression.spel.support.ReflectivePropertyAccessor$OptimalPropertyAccessor.read(ReflectivePropertyAccessor.java:708) at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:204) ... 82 more Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.springframework.expression.spel.support.ReflectivePropertyAccessor$OptimalPropertyAccessor.read(ReflectivePropertyAccessor.java:704) ... 83 more Caused by: org.hibernate.LazyInitializationException: could not initialize proxy [jpabook.jpashop.domain.Member#1] - no Session at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:176) at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:322) at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45) at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95) at jpabook.jpashop.domain.Member$HibernateProxy$rzzDK9hn.getName(Unknown Source) ... 88 more MemberService Interface입니다. memberService 입니다. OrderService 입니다. 따로 추가작업이 필요할까요??,,
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
<컬렉션 조회 최적화> - '엔티티를 DTO로 변환 - 페치 조인 최적화' 단원에서 궁금한 점이 있습니다.
안녕하세요 영한님 강좌 잘 보고있습니다 :) 다름이 아니라 해당 <컬렉션 조회 최적화> - '엔티티를 DTO로 변환 - 페치 조인 최적화' 에서 궁금한점이 생겨 질문을 남기게 되었습니다. 컬렉션 조회시 해당 엔티티에서 1개이상 컬렉션을 조회하지 말라고 하셨고 이게 조인되면서 테이블이 뻥튀기 되니 우리가 원했던(기대했던) 데이터가 깨져서 조회될 수 있고 이게 DB의 한계때문에 어쩔수없다는점은 이해되었습니다. 그러면 1개 이상의 컬렉션을 가져야 하는 경우는 설계의 오류인것일까요? 위와같은 구조에서 A테이블은 B 와 1:N 관계이고 B 테이블은 C테이블과 1:N 관계이며 A -> B -> C 형태로 종속되어있는 구조가 있다고 예를 들어보겠습니다. 그러면 아래와 같이 쿼리를 날리게 된다면 SELECT a FROM A a FETCH JOIN B b FETCH JOIN b.c c 이것도 A가 1개 이상의 컬렉션을 가지고 있다고 보는것이 맞을까요? 긴글 읽어주셔서 감사합니다 좋은하루되세요 :)