묻고 답해요
160만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
MSA와 사가 패턴을 찾아보면서 궁금했던 부분이 있어서 질문 남겨봅니다.
모든 자료가 그런 것은 아니지만 많은 MSA 관련 자료가 EDA (Event-Driven Architecture)를 이야기하고 있고, 카프카를 도입하면서 느슨하게 연결되어있고 원하는 메시지만 수신할 수 있도록 하는 구조로 설명을 하는 것 같습니다. (메시지 큐를 도입했을 때의 문제점에 대한 이야기는 별로 없고, 그 이상의 무언가를 찾거나 노하우를 구하기 쉽지 않은 듯 하네요.) 디커플링 자체는 상당히 좋은 장점 중 하나이지만, 개별 시스템으로 분리되면서 트랜잭션 관련해서도 고민이 많이 필요하고 연결하는 고리가 많아지는 만큼 신경써야 할 부분도 많을 것으로 보입니다. 그래서 들었던 질문이 몇 가지 있는데 마땅히 답을 구할만한 곳이 없었는데 이 쪽에서 관련된 질문에 답을 해주실 것 같아 달아봅니다. 1. 이벤트 소싱에 대해 맞게 이해한 것인지 ? 우선 이벤트 소싱이 CQRS, 비동기 처리와 많이 엮여서 나오는 주제이긴 하지만 이벤트 소싱 자체만을 두고 봤을 때에는 1) 이벤트의 모든 이력을 남기고 2) 핸들러가 이를 처리하는 것이 전부라고 이해해도 될까요 ?CQRS는 표면적으로는 변경과 질의를 분리하는 개념이지만, 이벤트 기록을 모두 재생해서 조회하는 것이 어려워서 질의와 변경을 분리하는 아이디어 때문에 이벤트 소싱에서 함께 언급되는 패턴으로 이해했고, 비동기 처리는 이벤트 소싱이 비동기 처리를 편하게 할 수 있는 환경 정도로만 이해했습니다. 제가 이해한게 맞는지 모르겠어서 잘 이해했는지 질문을 드리고 싶구요 ㅎㅎ 2. 짧은 시간 안에 처리되어야 하는 API도 MSA에 적합한가 ? 위에 제가 이해한 것이 맞다는 가정하에 말씀드리는 거긴 한데요. 예를 들면 만약에 OTT에서의 유료 영상 결제, 문서 파일 결제, 웹툰 등에서 결제하자마자 결과를 검증하고 사용해야 하는 과업이 있고, 이 과업을 단일 API로 처리하던 것을 MSA로 전환할 경우에 1) API, gRPC 등 네트워크 통신을 사용하는 MSA의 경우 : 코드나 개념적인 분리를 통해 서비스를 작게 쪼갤 수 있는 장점은 있지만 네트워크 이슈, 롤백 등 신경써야 할 문제가 많아진다 2) 카프카 등의 메시지 큐를 통한 MSA일 경우 : 카프카 자체의 문제 혹은 처리하는 개별 마이크로 서비스에 병목이 생기면 처리가 지연되며, 단일 API로 주고받던 경우에는 앱 수정이 불가피하다 (카프카를 사용하면 더더욱 이벤트 소싱을 고려할 수밖에 없고 PENDING 상태가 기존 앱에서 정의되지 않았기 때문에) 는 문제가 있을 것 같습니다. 아무래도 제가 카프카를 넣는 것이 우려가 되는 이유는 1) 각 서비스에서 발행한 카프카 메시지를 어떻게 추적하는지 쉽지 않다고 생각했고,2) 장애 포인트가 쪼개지는 서비스와 개념적으로 발생하는 연결의 갯수에 비례해서 많아지기 때문이라 생각했고,3) 또한 카프카를 통해서 처리하는 속도가 API로 처리하는 지금 속도 대비 느리게 세팅된 상태라 과하게 생각하는건가 싶기도 하고, 4) 앱에서 '서버의 아키텍쳐 변경을 위해 생긴 PENDING 상태에 대해 알고 있어야 하는가'에 대해서 고민이 많아서 그런 것 같습니다. 제가 MSA 관련해서는 경험이 없다보니 의견을 좀 들어보고 싶습니다. 3. 보상 트랜잭션과 관련하여각자의 로컬 트랜잭션만 보장하고 문제가 생기면 그게 반하는 트랜잭션을 새로 발행해서 상태를 상쇄시키는 형식인 것 같습니다. 상태 머신이 명확하게 구분된다면 보상 트랜잭션 구현이 용이하겠지만, 그렇지 않을 경우나 모호한 경우가 있을 것이라 생각됩니다. 또한 보상 트랜잭션이 실패하는 경우 더더욱 현상 파악이 쉽지 않을 것 같기도 하고, 구현하는 서비스마다 제각각이라 노하우를 구하기 쉽지 않을 것으로 보여서 구현 난이도가 꽤 올라갈 것으로 보이는데, 이런 부분을 보완할 수 있는 방법이 있을지 궁금합니다.
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
OrderITemDto 클래스 생성 위치
안녕하세요 좋은 영상 감사합니다. 다름이 아니라 OrderItemDto 는 OrderDto 안에서 사용하는 클래스이므로 OrderItemDto(내부 클래스) 의 다시 내부 클래스로 생성하는 것이 맞지 않나요? 영상에서는 OrderDto 와 동등한 레벨로 생성하셔서 궁금증이 들었습니다. 감사합니다^^
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
SpringBoot 버전 변경 후 매핑 문제
안녕하세요 강의를 보여 따라하던중 @NotEmpty 어노테이션이 안되는걸보고 질문을 검색하니 SpringBoot 버전을 변경해야 한다고 하셔서 build.gradle 파일을 교재에 나와있는데로 복붙하였습니다. 근데 그 이후부터 localhost:8080을 들어갈때 마다 아래와 같은 에러가 나면서 들어가지지를 않습니다. 코드에 문제가 있는건지 궁금합니다. 그리고 main밑에 생긴 generated 폴더도 무엇인지 궁금합니다. 2022-02-02 11:43:18.412 ERROR 12428 --- [nio-8080-exec-3] org.thymeleaf.TemplateEngine : [THYMELEAF][http-nio-8080-exec-3] Exception processing template "home": Error resolving fragment: "~{'fragments/footer' :: footer}": template or fragment could not be resolved (template: "home" - line 28, col 10) org.thymeleaf.exceptions.TemplateInputException: Error resolving fragment: "~{'fragments/footer' :: footer}": template or fragment could not be resolved (template: "home" - line 28, col 10) at org.thymeleaf.standard.expression.FragmentExpression.resolveExecutedFragmentExpression(FragmentExpression.java:619) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.standard.processor.AbstractStandardFragmentInsertionTagProcessor.computeFragment(AbstractStandardFragmentInsertionTagProcessor.java:379) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.standard.processor.AbstractStandardFragmentInsertionTagProcessor.doProcess(AbstractStandardFragmentInsertionTagProcessor.java:110) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.engine.ProcessorTemplateHandler.handleStandaloneElement(ProcessorTemplateHandler.java:918) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.engine.StandaloneElementTag.beHandled(StandaloneElementTag.java:228) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.engine.TemplateModel.process(TemplateModel.java:136) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:592) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:362) ~[thymeleaf-spring5-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:189) ~[thymeleaf-spring5-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1394) ~[spring-webmvc-5.3.2.jar:5.3.2] at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1139) ~[spring-webmvc-5.3.2.jar:5.3.2] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1078) ~[spring-webmvc-5.3.2.jar:5.3.2] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:961) ~[spring-webmvc-5.3.2.jar:5.3.2] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.2.jar:5.3.2] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.2.jar:5.3.2] at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.41.jar:4.0.FR] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.2.jar:5.3.2] at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.41.jar:4.0.FR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.2.jar:5.3.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.2.jar:5.3.2] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.2.jar:5.3.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.2.jar:5.3.2] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.2.jar:5.3.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.2.jar:5.3.2] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na] 2022-02-02 11:43:18.413 ERROR 12428 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: Error resolving fragment: "~{'fragments/footer' :: footer}": template or fragment could not be resolved (template: "home" - line 28, col 10)] with root cause org.thymeleaf.exceptions.TemplateInputException: Error resolving fragment: "~{'fragments/footer' :: footer}": template or fragment could not be resolved (template: "home" - line 28, col 10) at org.thymeleaf.standard.expression.FragmentExpression.resolveExecutedFragmentExpression(FragmentExpression.java:619) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.standard.processor.AbstractStandardFragmentInsertionTagProcessor.computeFragment(AbstractStandardFragmentInsertionTagProcessor.java:379) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.standard.processor.AbstractStandardFragmentInsertionTagProcessor.doProcess(AbstractStandardFragmentInsertionTagProcessor.java:110) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.engine.ProcessorTemplateHandler.handleStandaloneElement(ProcessorTemplateHandler.java:918) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.engine.StandaloneElementTag.beHandled(StandaloneElementTag.java:228) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.engine.TemplateModel.process(TemplateModel.java:136) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:592) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:362) ~[thymeleaf-spring5-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:189) ~[thymeleaf-spring5-3.0.11.RELEASE.jar:3.0.11.RELEASE] at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1394) ~[spring-webmvc-5.3.2.jar:5.3.2] at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1139) ~[spring-webmvc-5.3.2.jar:5.3.2] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1078) ~[spring-webmvc-5.3.2.jar:5.3.2] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:961) ~[spring-webmvc-5.3.2.jar:5.3.2] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.2.jar:5.3.2] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.2.jar:5.3.2] at javax.servlet.http.HttpServlet.service(HttpServlet.java:626) ~[tomcat-embed-core-9.0.41.jar:4.0.FR] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.2.jar:5.3.2] at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.41.jar:4.0.FR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.2.jar:5.3.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.2.jar:5.3.2] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.2.jar:5.3.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.2.jar:5.3.2] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.2.jar:5.3.2] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.2.jar:5.3.2] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.41.jar:9.0.41] at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
안녕하세요! MSA에 대해서
안녕하세요! 궁금한게 있습니다. 저희회사에서는 프로젝트가 멀티모듈로 되어있습니다. 그리고 CMS(운영관리 모듈), API, COMMENT 모듈 이렇게 3개의 애플리케이션 모듈을 사내 도커레지스트리에 도커 이미지로 올리고 AWS에 각각 3개의 모듈을 띄우는데요! 이게 음.. 데이터베이스는 한개로 씁니다. 그러니까 각 3개의 데이터베이스가 따로 한개씩 있는 것이아닌 마스터 하나에 슬래이브 1개의 레플리카로 구성되어있습니다. 이것또한 MSA라고 할수있을까요? 신입이라 아직 정확하게는 모르겠지만 저는 DB도 각 애플리케이션 마다있어야한다고 보고 그게 MSA라고 생각하고 있거든요.! 선생님의 의견이 궁금합니다! 감사합니다.
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
update 메소드가 void 인것과 관련된 질문 드립니다.
안녕하세요. update 메소드는 커맨드 쿼리 분리 원칙에 따라서 member 객체를 반환하지 말고 void로 반환값이 없게 하거나 id정도만 반환하라고 하셨습니다. 1. 커맨드가 수정이니 쿼리로 member를 찾지 말아야 한다고 하셨는데 findOne 메소드에서 어차피 member를 찾아야 하는 것 아닌가요? 2. update 메소드 외에도 사실 모든 메소드에서 void나 id만 반환해야 하는 것인가요? 다른 메소드도 등록, 수정, 삭제 등등 멤버를 조회하는 것이 커맨드가 아닌 것 같은데, 그렇다면 일반적으로 반환을 id만 해주는 것이 좋은가요? 감사합니다.
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
안녕하세요 영한님 강의를 벗어난 주제 이긴한대 궁금한게 생겨서 질문드립니다.
유저와 팔로우 팔로잉 Entity 를 구현하려고 하는데 이렇게 하는게 맞는건지 잘 모르겠어서 질문드립니다.. 조금이라도 힌트를 주신다면 정말 감사할것 같네요!!
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
BatchSize, Batch Fetch Size 옵션이 적용되지 않는 문제
안녕하세요 영한님 강의 잘 듣고 있습니다! 해당 강의에서 글로벌전략을 지연로딩 설정후 Order -(one to Many) - OrderItemList -(Many To One)- Item 연관관계의 엔티티에 BatchSize, Batch Fetch Size 옵션을 적용해 3계층 깊이를 가진 엔티티 그래프를 조회하면 총 쿼리가 계층별로 하나씩, 3개 날라간다고 이해를 했습니다. 그런데 jdk 11, 스프링 Data Jpa와 mysql 등 약간의 환경 변화후 같은 예제로 테스트해보니 1. order 쿼리 2. orderItemList의 N개 쿼리(강의에서는 총 2개) 3. 이후 in절로 묶인 item 쿼리가 위의 N개쿼리때문에 N개 총 5개의 쿼리가 날라가는 현상이 발생했습니다. 요약하면 첫 연관 엔티티 orderitem은 batchsize 옵션이 적용되지 않아 N개의 쿼리가 날라가고 이후에 배치 옵션이 적용되어 각각 in절로 묶인 item 엔티티 쿼리가 날라가고있습니다. 이것저것 조작하다가 서비스단에서 transaction 어노테이션을 제거하니 강의에서처럼 엔티티 그래프 계층별로 한개씩 쿼리가 3개로 바뀌어 날라가는데 이유를 잘 모르겠습니다. transaction(Readonly = true) 일때도 정상적으로 쿼리가 3개 날라가는거보면 transaction(Readonly = false) 상황에서만 발생하는 문제같은데 혹시 원인을 알수 있을까요? 해당 문제를 고민하는 과정을 블로그에 글로 작성했는데 참조해서 정확한 원인을 알려주시면 정말 감사하겠습니다. https://www.jiniaslog.co.kr/article/view?articleId=559 언제나 양질의 강의 제공해주셔서 정말 감사하고 새해복 많이 받으세요!
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
주문 목록 뷰에서 사용한 코드 관련 질문입니다.
강의를 다시 복습하면서 코드를 다시 유심히 보다가 발견하지 못한 부분을 발견해서 질문드립니다 주문 목록을 타임리프를 이용해서 뿌리는 코드는 다음과 같은데요 <tr th:each="item : ${orders}"> <td th:text="${item.id}"></td> <td th:text="${item.member.name}"></td> <td th:text="${item.orderItems[0].item.name}"></td> <td th:text="${item.orderItems[0].orderPrice}"></td> <td th:text="${item.orderItems[0].count}"></td> <td th:text="${item.status}"></td> <td th:text="${item.orderDate}"></td> <td> <a th:if="${item.status.name() == 'ORDER'}" href="#" th:href="'javascript:cancel('+${item.id}+')'" class="btn btn-danger">CANCEL</a> </td> </tr> 여기서 의문점이 Order와 Member는 다대일 관계이기 때문에 Order 리스트에 대해서 Order id와 Member 정보는 저렇게 출력하는게 가능한데 Order와 OrderItem은 1대다 관계인데 orderItems[0] 형태로 0 인덱스만 주었는데 출력이 되어있는데요 orderItems는 리스트인데 인덱스는 0만 주어서 출력하는 부분에서 타임리프 가이드를 보긴 했는데 이런 케이스에 대해서는 왜 이런식으로 코드가 나오는지 이해 안돼서 질문드립니다. 왜냐하면 저렇게 하면 하나의 Order에 대해서 Orderitem이 하나 밖에 나오지 않아서요 검증쿼리는 다음과 같이 던져서 검증 했구요 SELECT M.NAME, O.ORDER_ID, I.ORDER_PRICE, I.COUNT, IT.NAME FROM ORDERS O , ORDER_ITEM I , MEMBER M , ITEM IT WHERE 1=1 AND O.ORDER_ID = I.ORDER_ID AND M.MEMBER_ID = O.MEMBER_ID AND IT.ITEM_ID = I.ITEM_ID ORDER BY M.NAME ASC, O.ORDER_ID ASC, IT.NAME ASC, I.COUNT ASC 출력결과는 다음과 같습니다. 저런 상황이 발생하지 않도록 알맞게 처리하기 위해서는 view에 뿌려줄 수 있도록 적절한 DTO로 변환해서 뿌려줘야하는 것이 맞는지 궁금합니다.
-
미해결실전! Querydsl
fetchResults, fetchCount deprecated
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]fetchResults, fetchCount deprecated 되었는데, 그래도 알려주신대로 써야할지 아님 다른 대안이 있는지 궁금합니다.
-
해결됨실전! Querydsl
JPA, Querdsl 환경에서 팬텀리드는 어떻게 방지하나요?
안녕하세요. 초보개발자 명아주입니다. 새해복많이 받으세요! 이번에 QueryDSL 를 이용한 페이징 기능을 공부하면서 느꼈던 의문점이 있습니다. 일반적인 경우 쿼리가 2번 나가게 되는데, 그 사이에 팬텀리드가 발생한다면 어떻게 막을수 있을지 입니다. 어디서 언뜻 보기로, JPA 가 어플리케이션 레벨에서 Repeatable Read를 보장해준다고 봤었던것 같습니다. 물론 Repeatable Read더라도 phantom Read가 발생하는 걸로 알고 있지만요. 그래서 실무에서 이런 phantom read가 발생하는 걸 겪으신 경험이나 어떻게 해결하셨었는지 궁금합니다! 감사합니다!
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
비교적 최신 버전에서 에러가 발생합니다.
에러 내용을 자세하게 이해하진 못했지만 사용중인 임베디드 톰캣 버전에서 `hasIpAddress` 를 찾지 못하는 것 같습니다.스프링 버전은 2.6.2 사용중이고, starter-security 그대로 사용하고 있습니다. `hasIpAddress` 대신 다른 메서드를 사용하면 가능은 한데 의도한 것과 다른 것 같아서 남깁니다. java.lang.UnsupportedOperationException: public abstract java.lang.String javax.servlet.ServletRequest.getRemoteAddr() is not supported at org.springframework.security.web.FilterInvocation$UnsupportedOperationExceptionInvocationHandler.invoke(FilterInvocation.java:326) ~[spring-security-web-5.6.1.jar:5.6.1] at com.sun.proxy.$Proxy150.getRemoteAddr(Unknown Source) ~[na:na] at javax.servlet.ServletRequestWrapper.getRemoteAddr(ServletRequestWrapper.java:241) ~[tomcat-embed-core-9.0.56.jar:4.0.FR] at org.springframework.security.web.util.matcher.IpAddressMatcher.matches(IpAddressMatcher.java:65) ~[spring-security-web-5.6.1.jar:5.6.1]
-
해결됨실전! Querydsl
QueryProjection 수동으로 만들면 어떨까요?
안녕하세요! 초보개발자 명아주입니다. QueryProejction 사용 시, DTO가 QueryDSL 에 의존적인게 단점이라고 하셨습니다. 그 외에는 컴파일 레벨에서 체크할 수 있다는게 정말 큰 장점인 것 같습니다. 그래서 혹시 의존성을 갖지 않으면서 이걸 사용할 방법이 없을까? 라는 의문으로 한가지 테스트를 해보고 찾은 해결 방법은 CustomQUserDto 를 직접 만들어서 쓰면 어떨까 싶습니다. CustomQUserDto는 레포지토리 계층에서만 쓰고, 반환값은 UserDto로 나가니까 서비스에서는 CustomQUserDto를 몰라도 상관이 없을것 같다고 생각했습니다. package study.querydsl.repository.dto;import com.querydsl.core.types.ConstructorExpression;import com.querydsl.core.types.Expression;import com.querydsl.dto.UserDto;public class CustomQUserDto extends ConstructorExpression<UserDto> { public CustomQUserDto(Expression<String> name, Expression<Integer> age) { super(UserDto.class, new Class<?>[]{String.class, int.class}, name, age); //혹은 심플하게 super(UserDto.class, name, age); 라고 해도 됩니다. }} 샘플코드는 자동생성된 QMemberDto를 참고해서 이렇게 짜봤습니다. serialVersionUID는 어떻게 처리해야될지 몰라서 없앴고 없어도 테스트 상에서는 문제없었습니다. @Testpublic void findUserDtoByManualQueryProjection() throws Exception { //given //when List<UserDto> result = query .select(new CustomQUserDto(member.username, member.age)) .from(member) .fetch(); //then for (UserDto userDto : result) { System.out.println("userDto = " + userDto); }} 위처럼 테스트를 진행해봤을때 정상적으로 동작하는걸 확인했는데요. 혹시 이런식으로 QueryProjectionDto를 수동으로 만들어서 사용하시는 경우가 있으신지 궁금합니다. 감사합니다. 명아주 드림 새해 복많이 받으세요~~~~ p.s 한가지 질문드리고 싶은점이 있는데, 강의들으면서 따라 치는 코드를 깃허브에 올리고 있는데 혹시 문제가 된다면 비공개 레포로 변경하려고 합니다. 답변 주시는 대로 원하시는대로 처리하겠습니다!
-
미해결실전! 스프링 데이터 JPA
count query
안녕하세요 개발자님 스프링 커리큘럼 수강중인 학생입니다. 다름이 아니라 수업중 헷갈리는 부분이 있어 질문드립니다. 제가 알기로는 일대다 관계에서 left join을 하면 데이터가 뻥튀기(?) 된다고 알고 있는데 이때 join을 안하고 count쿼리를 따로 날리면 의도한 갯수가 안나올것 같다는 생각이 들었습니다. 그럼 team을 기준으로 left join을 할때는 count query를 따로 사용하면 안되는게 맞나요?? 제가 잘 이해한건지 궁금합니다. 글 읽어주셔 감사합니다. 좋은하루 되십시오
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
주문 취소 Cancel 버튼이 작동하지 않음
주문 취소 기능을 가진 cancel 버튼을 클릭해도 주문 취소 상태로 변하지 않습니다. 무엇이 문제일까요? cancel 버튼 누를 시 콘솔 2022-01-28 09:45:17.700 DEBUG 7444 --- [nio-8080-exec-4] org.hibernate.SQL : select order0_.order_id as order_id1_6_0_, order0_.delivery_id as delivery4_6_0_, order0_.member_id as member_i5_6_0_, order0_.order_date as order_da2_6_0_, order0_.status as status3_6_0_ from orders order0_ where order0_.order_id=? 2022-01-28 09:45:17.700 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [3] 2022-01-28 09:45:17.702 INFO 7444 --- [nio-8080-exec-4] p6spy : #1643330717702 | took 1ms | statement | connection 18| url jdbc:h2:tcp://localhost/~/jpashop select order0_.order_id as order_id1_6_0_, order0_.delivery_id as delivery4_6_0_, order0_.member_id as member_i5_6_0_, order0_.order_date as order_da2_6_0_, order0_.status as status3_6_0_ from orders order0_ where order0_.order_id=? select order0_.order_id as order_id1_6_0_, order0_.delivery_id as delivery4_6_0_, order0_.member_id as member_i5_6_0_, order0_.order_date as order_da2_6_0_, order0_.status as status3_6_0_ from orders order0_ where order0_.order_id=3; 2022-01-28 09:45:17.703 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([delivery4_6_0_] : [BIGINT]) - [4] 2022-01-28 09:45:17.703 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([member_i5_6_0_] : [BIGINT]) - [1] 2022-01-28 09:45:17.704 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_da2_6_0_] : [TIMESTAMP]) - [2022-01-28T09:43:00.843051] 2022-01-28 09:45:17.704 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([status3_6_0_] : [VARCHAR]) - [ORDER] 2022-01-28 09:45:17.706 TRACE 7444 --- [nio-8080-exec-4] org.hibernate.type.CollectionType : Created collection wrapper: [jpabook.jpashop.domain.Order.orderItems#3] 2022-01-28 09:45:17.707 DEBUG 7444 --- [nio-8080-exec-4] org.hibernate.SQL : select delivery0_.delivery_id as delivery1_2_0_, delivery0_.city as city2_2_0_, delivery0_.street as street3_2_0_, delivery0_.zipcode as zipcode4_2_0_, delivery0_.status as status5_2_0_ from delivery delivery0_ where delivery0_.delivery_id=? 2022-01-28 09:45:17.708 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [4] 2022-01-28 09:45:17.710 INFO 7444 --- [nio-8080-exec-4] p6spy : #1643330717710 | took 0ms | statement | connection 18| url jdbc:h2:tcp://localhost/~/jpashop select delivery0_.delivery_id as delivery1_2_0_, delivery0_.city as city2_2_0_, delivery0_.street as street3_2_0_, delivery0_.zipcode as zipcode4_2_0_, delivery0_.status as status5_2_0_ from delivery delivery0_ where delivery0_.delivery_id=? select delivery0_.delivery_id as delivery1_2_0_, delivery0_.city as city2_2_0_, delivery0_.street as street3_2_0_, delivery0_.zipcode as zipcode4_2_0_, delivery0_.status as status5_2_0_ from delivery delivery0_ where delivery0_.delivery_id=4; 2022-01-28 09:45:17.710 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([city2_2_0_] : [VARCHAR]) - [qq] 2022-01-28 09:45:17.710 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([street3_2_0_] : [VARCHAR]) - [qq] 2022-01-28 09:45:17.710 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([zipcode4_2_0_] : [VARCHAR]) - [11111] 2022-01-28 09:45:17.711 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([status5_2_0_] : [VARCHAR]) - [null] 2022-01-28 09:45:17.711 DEBUG 7444 --- [nio-8080-exec-4] 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-01-28 09:45:17.712 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [3] 2022-01-28 09:45:17.713 INFO 7444 --- [nio-8080-exec-4] p6spy : #1643330717713 | took 0ms | statement | connection 18| url jdbc:h2:tcp://localhost/~/jpashop 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=3; 2022-01-28 09:45:17.713 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_it1_5_1_] : [BIGINT]) - [5] 2022-01-28 09:45:17.714 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([count2_5_1_] : [INTEGER]) - [3] 2022-01-28 09:45:17.714 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([item_id4_5_1_] : [BIGINT]) - [2] 2022-01-28 09:45:17.714 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_id5_5_1_] : [BIGINT]) - [3] 2022-01-28 09:45:17.714 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_pr3_5_1_] : [INTEGER]) - [1111] 2022-01-28 09:45:17.714 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_id5_5_0_] : [BIGINT]) - [3] 2022-01-28 09:45:17.714 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_it1_5_0_] : [BIGINT]) - [5] 2022-01-28 09:45:17.715 DEBUG 7444 --- [nio-8080-exec-4] 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-01-28 09:45:17.716 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [2] 2022-01-28 09:45:17.717 INFO 7444 --- [nio-8080-exec-4] p6spy : #1643330717717 | took 0ms | statement | connection 18| url jdbc:h2:tcp://localhost/~/jpashop 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=2; 2022-01-28 09:45:17.717 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([dtype1_3_0_] : [VARCHAR]) - [B] 2022-01-28 09:45:17.718 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([name3_3_0_] : [VARCHAR]) - [add] 2022-01-28 09:45:17.719 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([price4_3_0_] : [INTEGER]) - [1111] 2022-01-28 09:45:17.719 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([stock_qu5_3_0_] : [INTEGER]) - [1108] 2022-01-28 09:45:17.719 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([author8_3_0_] : [VARCHAR]) - [dffdsf] 2022-01-28 09:45:17.719 TRACE 7444 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicExtractor : extracted value ([isbn9_3_0_] : [VARCHAR]) - [3432423] 2022-01-28 09:45:17.720 TRACE 7444 --- [nio-8080-exec-4] org.hibernate.type.CollectionType : Created collection wrapper: [jpabook.jpashop.domain.item.Item.categories#2] 2022-01-28 09:45:17.722 INFO 7444 --- [nio-8080-exec-4] p6spy : #1643330717722 | took 0ms | commit | connection 18| url jdbc:h2:tcp://localhost/~/jpashop ; 2022-01-28 09:45:17.749 DEBUG 7444 --- [nio-8080-exec-3] org.hibernate.SQL : select order0_.order_id as order_id1_6_, order0_.delivery_id as delivery4_6_, order0_.member_id as member_i5_6_, order0_.order_date as order_da2_6_, order0_.status as status3_6_ from orders order0_ inner join member member1_ on order0_.member_id=member1_.member_id limit ? 2022-01-28 09:45:17.750 INFO 7444 --- [nio-8080-exec-3] p6spy : #1643330717750 | took 0ms | statement | connection 19| url jdbc:h2:tcp://localhost/~/jpashop select order0_.order_id as order_id1_6_, order0_.delivery_id as delivery4_6_, order0_.member_id as member_i5_6_, order0_.order_date as order_da2_6_, order0_.status as status3_6_ from orders order0_ inner join member member1_ on order0_.member_id=member1_.member_id limit ? select order0_.order_id as order_id1_6_, order0_.delivery_id as delivery4_6_, order0_.member_id as member_i5_6_, order0_.order_date as order_da2_6_, order0_.status as status3_6_ from orders order0_ inner join member member1_ on order0_.member_id=member1_.member_id limit 1000; 2022-01-28 09:45:17.750 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_id1_6_] : [BIGINT]) - [3] 2022-01-28 09:45:17.751 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([delivery4_6_] : [BIGINT]) - [4] 2022-01-28 09:45:17.751 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([member_i5_6_] : [BIGINT]) - [1] 2022-01-28 09:45:17.751 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_da2_6_] : [TIMESTAMP]) - [2022-01-28T09:43:00.843051] 2022-01-28 09:45:17.752 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([status3_6_] : [VARCHAR]) - [ORDER] 2022-01-28 09:45:17.753 TRACE 7444 --- [nio-8080-exec-3] org.hibernate.type.CollectionType : Created collection wrapper: [jpabook.jpashop.domain.Order.orderItems#3] 2022-01-28 09:45:17.755 INFO 7444 --- [nio-8080-exec-3] p6spy : #1643330717755 | took 0ms | commit | connection 19| url jdbc:h2:tcp://localhost/~/jpashop ; 2022-01-28 09:45:17.776 DEBUG 7444 --- [nio-8080-exec-3] org.hibernate.SQL : select member0_.member_id as member_i1_4_0_, member0_.city as city2_4_0_, member0_.street as street3_4_0_, member0_.zipcode as zipcode4_4_0_, member0_.name as name5_4_0_ from member member0_ where member0_.member_id=? 2022-01-28 09:45:17.776 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [1] 2022-01-28 09:45:17.777 INFO 7444 --- [nio-8080-exec-3] p6spy : #1643330717777 | took 0ms | statement | connection 19| url jdbc:h2:tcp://localhost/~/jpashop select member0_.member_id as member_i1_4_0_, member0_.city as city2_4_0_, member0_.street as street3_4_0_, member0_.zipcode as zipcode4_4_0_, member0_.name as name5_4_0_ from member member0_ where member0_.member_id=? select member0_.member_id as member_i1_4_0_, member0_.city as city2_4_0_, member0_.street as street3_4_0_, member0_.zipcode as zipcode4_4_0_, member0_.name as name5_4_0_ from member member0_ where member0_.member_id=1; 2022-01-28 09:45:17.778 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([city2_4_0_] : [VARCHAR]) - [qq] 2022-01-28 09:45:17.778 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([street3_4_0_] : [VARCHAR]) - [qq] 2022-01-28 09:45:17.778 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([zipcode4_4_0_] : [VARCHAR]) - [11111] 2022-01-28 09:45:17.778 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([name5_4_0_] : [VARCHAR]) - [qq] 2022-01-28 09:45:17.778 TRACE 7444 --- [nio-8080-exec-3] org.hibernate.type.CollectionType : Created collection wrapper: [jpabook.jpashop.domain.Member.orders#1] 2022-01-28 09:45:17.780 DEBUG 7444 --- [nio-8080-exec-3] 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-01-28 09:45:17.780 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [3] 2022-01-28 09:45:17.782 INFO 7444 --- [nio-8080-exec-3] p6spy : #1643330717782 | took 1ms | statement | connection 19| url jdbc:h2:tcp://localhost/~/jpashop 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=3; 2022-01-28 09:45:17.782 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_it1_5_1_] : [BIGINT]) - [5] 2022-01-28 09:45:17.783 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([count2_5_1_] : [INTEGER]) - [3] 2022-01-28 09:45:17.783 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([item_id4_5_1_] : [BIGINT]) - [2] 2022-01-28 09:45:17.783 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_id5_5_1_] : [BIGINT]) - [3] 2022-01-28 09:45:17.783 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_pr3_5_1_] : [INTEGER]) - [1111] 2022-01-28 09:45:17.783 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_id5_5_0_] : [BIGINT]) - [3] 2022-01-28 09:45:17.783 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([order_it1_5_0_] : [BIGINT]) - [5] 2022-01-28 09:45:17.784 DEBUG 7444 --- [nio-8080-exec-3] 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-01-28 09:45:17.787 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [2] 2022-01-28 09:45:17.788 INFO 7444 --- [nio-8080-exec-3] p6spy : #1643330717788 | took 0ms | statement | connection 19| url jdbc:h2:tcp://localhost/~/jpashop 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=2; 2022-01-28 09:45:17.788 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([dtype1_3_0_] : [VARCHAR]) - [B] 2022-01-28 09:45:17.789 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([name3_3_0_] : [VARCHAR]) - [add] 2022-01-28 09:45:17.789 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([price4_3_0_] : [INTEGER]) - [1111] 2022-01-28 09:45:17.789 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([stock_qu5_3_0_] : [INTEGER]) - [1108] 2022-01-28 09:45:17.789 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([author8_3_0_] : [VARCHAR]) - [dffdsf] 2022-01-28 09:45:17.789 TRACE 7444 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicExtractor : extracted value ([isbn9_3_0_] : [VARCHAR]) - [3432423] 2022-01-28 09:45:17.789 TRACE 7444 --- [nio-8080-exec-3] org.hibernate.type.CollectionType : Created collection wrapper: [jpabook.jpashop.domain.item.Item.categories#2] 소스코드 : https://github.com/AmyLim328/springboot-jpa-jpashop
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
V4 질문있습니다!
안녕하세요 영한님 서포터즈님들 V4에서 OrderQueryRepository 에 있는 findOrders 메서드에 대한 질문입니다. lazy인데 어떻게 member와 delivery가 같이 조회되는지 이해가 되질 않습니다.. m.name을 알기위해 member 엔티티를 select 해야한다고 생각을 했습니다 혹시 어느 부분이랑 제가 헷갈리는걸까요? 해당 단원 qna에서 해당 질문과 비슷한 게 있었는데 fetch join에 대해서만 말씀해주셔서 궁금해서 여쭤보게됐습니다 감사합니다 안녕하세요!! 질문 드리고 답을 기다리는 동안에 계속 찾아보고 생각해봤는데아직 저 자신한테 납득이 안되서요,, 혹시 맞는지 여쭤보고 싶습니다 API 개발 고급 - 지연 로딩과 조회 성능 최적화 강의에서 V4를 보고왔습니다 제가 의심한 부분은 "일반적인 SQL을 사용할 대 처럼 원하는 값을 선택해서 조회"입니다. 첫 번째 쿼리에 대한 데이터는 이렇게 되어있습니다 지연로딩은 프록시 객체를 만들어서 해당 엔티티의 필드를 사용할 때 DB에서 엔티티를 조회하는 것인데, 바로 DTO를 조회하는 것은 JOIN된 DB 값에서 member의 이름, delivery address 을 바로 뽑아서 값을 가져오기 때문에 JPA에서 엔티티를 조회하지 않아도 값을 알 수 있으며, 다른 select 쿼리가 나가지 않게 되는걸까요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
주문 취소 Cancel 작동 오류
주문 취소 실행이 안돼요. 소스코드 : https://github.com/AmyLim328/springboot-jpa-jpashop
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
연관관계 편의 메소드, 생성 메소드에 대해 질문드려요!!
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요. 항상 강의 잘 보고 있습니다. 다름이 아니라 연관관계 편의 메소드와 생성 메소드에 관해 궁금증이 생겨 질문을 드릴려고 합니다. Entity 필드에서 가급적이면 setter 를 지양해야 한다고 알고 있습니다. 그래서 setter 를 쓰지 않고 오직 builder 를 통해 연관관계 편의 메소드와 생성 메소드를 정의할 순 없을까 고민했습니다. 아래는 setter 를 쓰지않고 builder 만 써서 작성해본 코드입니다. <Delivery builder> @Builderprivate Delivery(Order order, Address address, DeliveryStatus deliveryStatus) { this.order = order; this.address = address; this.deliveryStatus = deliveryStatus; } <OrderItem builder> @Builderprivate OrderItem(Order order, Item item, int orderPrice, int orderCount) { this.order = order; this.item = item; this.orderPrice = orderPrice; this.orderCount = orderCount; } <Order builder & createOrder> @Builderprivate Order(Member member, Delivery delivery, List<OrderItem> orderItems, LocalDateTime orderDate, OrderStatus orderStatus) { this.member = member; this.delivery = delivery; this.orderItems = orderItems; this.orderDate = orderDate; this.orderStatus = orderStatus; //== 연관관계 편의 메소드(?) ==// Delivery.builder().order(this).build(); OrderItem.builder().order(this).build(); }//== 생성 메소드 ==//public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems) { return builder() .member(member).delivery(delivery).orderItems(Arrays.asList(orderItems)).orderDate(LocalDateTime.now()).orderStatus(OrderStatus.ORDER).build(); } 위에서 보시다시피 Delivery 와 OrderItem 에서 builder 를 각각 생성했습니다. 그리고 Order 의 builder 안에 연관관계 편의 메소드(?)를 추가하고, 생성 메소드에서 builder 를 이용하여 order 를 빌드한 후 리턴을 시켜줬습니다. 혹시 이렇게 작성해도 별 문제 없을까요...??? 제 부족한 질문을 읽어주셔서 감사합니다...!
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
orderitem.size 에서 같은 인스턴스(엔티티)가 중복 저장되는 문제
orderItems.size 를 테스트 할때 같은 인스턴스가 orderitem에 중복저장 되는 것 같습니다. 1이 아닌 2가 나와요. List<OrderItem> orderItems = getOrder.getOrderItems(); for(OrderItem orderItem : orderItems) { sout (orderItem); } 하니까 같은 래퍼런스값을 가진 게 2번 똑같이 나왔습니다. 어디서 발생한건지 찾을 수 없어서 질문드려요
-
해결됨실전! 스프링 데이터 JPA
save하고 update할때 혼란이 있습니다
안녕하세요. 초보 개발자 명아주입니다. 궁금한게 있어서 문의드립니다. 제가 공부하다가 놓친걸 수도 있는데 아직 잘 이해가 안되는 부분이 하나 있습니다. 예를들어서 Member member = new Member(); member.setName("hello"); em.persist(member); member.setName("jpa"); 이런 코드가 있을때 예상 : member가 영속성 컨텍스트에 들어감 트랜잭션 종료 때, flush할때 변경감지까지 포함해서 한 번의 쿼리만 나감 insert into member values (1, 'jpa'); 실제 : insert into member values (1, 'hello'); update member set name = 'jpa'; 영속성 컨텍스트에 들어가있다가 아직 플러시 되지 않은 상태에서 변경되면 마지막에 변경된 사항으로 insert 한번만 나갈 줄 알았는데 실제 동작은 insert, 그리고 변경감지에 의한 update가 발생하더라구요. 저번에 말씀하셨던 것중 얼핏 기억나는 스냅샷? 같은 걸로 영속성에 들어간 상태를 스냅샷 찍어놓고 그거에 대한 insert 쿼리가 나가고 그 후에 변경감지를 처리하는건가요?? 궁금합니다! 감사합니다.
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
테스트 코드 autowired 질문입니다
안녕하세요. Test 코드에서 public class MemberRepositoryTest { @Autowired MemberRepository memberRepository; 이렇게 돼있던데요. 여기서 @Autowired로 주입을 받아야 하는 이유가 무엇인가요? 그냥 MemberRepository memberRepository = new MemberRepository(); 로 해도 될거같아서 해봤는데 에러가 나더라고요... Member 클래스는 그냥 Member member = new Member(); 이 형태로 쓸 수 있는데, MemberRepository 클래스는 어차피 예제 상황이라 싱글톤으로 안써도 되는 상황인데도 왜 굳이 의존성 주입으로만 해야하는건지 궁금합니다.