25%
66,000원
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
람다 부분을 람다 없이 만들려면 어떻게 해야할까요?
삭제된 글입니다
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
Fetch join시 fetch type
안녕하세요, 김영한 강사님. 만약 패치 조인으로 연관 엔티티를 한번에 불러오게 되면, fetchType=LAZY로 정의했지만 실제로는 EAGER(즉시 로딩)와 같이 동작한다고 이해하는 것이 맞을까요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
select 조회 성능 관련 질문
1. 일반 db에서 select * from 보다 select 칼럼명 from 보통 후자의 방법으로 원하는 칼럼들만 부르는 게 성능 면에서 더 뛰어난 게 아닌지 궁금합니다. 2. 복잡한 테이블에서 전체 칼럼의 갯수가 20~30개가 넘어가면 fetch join 방식보다 DTO로 직접 조회하시는 방법을 쓰시는지 궁금합니다. (fetch join으로 해도 성능이 원하는 만큼 안 나올때 DTO로 직접 조회 하시는건가요?) 3. JPA 관점에서 복잡한 테이블이나, 컬렉션 조회는 강좌에서처럼 최적화를 할 수 있지만. 일반 테이블 jpa에서는 보통 전체 엔티티를 불러올 수 밖에 없던데 1)전체 엔티티를 조회했을 때와 2)원하는 칼럼들만 조회했을 때의 성능차이가 미비한지 궁금합니다. 4. spring data jpa에서 Projections로 원하는 칼럼만 조회할 수 있던데 실무에서는 엔티티가 한 개이면서도 단순할 때 성능을 위해 많이 사용하시는지 궁금합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
fetchjoin 관련해서
복잡한 테이블에서 @XToOne 칼럼을 조회할 때는 lazy loading으로 변환 후 fetchjoin을 권장하시던데 등록, 수정, 삭제할 때도 1) N+1 문제가 발생하는지 2)fetch join을 사용해야 되는지 궁금합니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
DTO에서 @Setter 열어두는 것에 관해서
엔티티에는 여기저기 값을 변경할 수 있어서 실무에서는 setter를 꼭 닫아두라고 하셨는데 DTO에는 @AllArgsConstructor나 @Setter를 아무렇게나 열어두어도 상관 없나요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
h2 database 연결이 안되요
안녕하세요 어떻게 어떻게 해서 잘 사용을 했는데 갑자기 연결이 안됩니다. 2021-06-28 10:19:27.477 INFO 20176 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2021-06-28 10:19:30.533 ERROR 20176 --- [ restartedMain] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Exception during pool initialization. org.h2.jdbc.JdbcSQLNonTransientConnectionException: Connection is broken: "java.net.SocketTimeoutException: connect timed out: localhost" [90067-200] at org.h2.message.DbException.getJdbcSQLException(DbException.java:622) ~[h2-1.4.200.jar:1.4.200] at org.h2.message.DbException.getJdbcSQLException(DbException.java:429) ~[h2-1.4.200.jar:1.4.200] at org.h2.message.DbException.get(DbException.java:194) ~[h2-1.4.200.jar:1.4.200] at org.h2.engine.SessionRemote.connectServer(SessionRemote.java:439) ~[h2-1.4.200.jar:1.4.200] at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:321) ~[h2-1.4.200.jar:1.4.200] at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:173) ~[h2-1.4.200.jar:1.4.200] at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:152) ~[h2-1.4.200.jar:1.4.200] at org.h2.Driver.connect(Driver.java:69) ~[h2-1.4.200.jar:1.4.200] at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) ~[HikariCP-4.0.3.jar:na] at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:364) ~[HikariCP-4.0.3.jar:na] at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:206) ~[HikariCP-4.0.3.jar:na] at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:476) ~[HikariCP-4.0.3.jar:na] at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:561) ~[HikariCP-4.0.3.jar:na] at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115) ~[HikariCP-4.0.3.jar:na] at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) ~[HikariCP-4.0.3.jar:na] at com.p6spy.engine.spy.P6DataSource.getConnection(P6DataSource.java:303) ~[p6spy-3.8.2.jar:na] at com.github.gavlyukovskiy.boot.jdbc.decorator.DataSourceDecoratorInterceptor.invoke(DataSourceDecoratorInterceptor.java:53) ~[datasource-decorator-spring-boot-autoconfigure-1.5.6.jar:na] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.8.jar:5.3.8] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.8.jar:5.3.8] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692) ~[spring-aop-5.3.8.jar:5.3.8] at com.zaxxer.hikari.HikariDataSource$$EnhancerBySpringCGLIB$$e4eb3b59.getConnection(<generated>) ~[HikariCP-4.0.3.jar:na] at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.lambda$h2Console$0(H2ConsoleAutoConfiguration.java:67) ~[spring-boot-autoconfigure-2.5.1.jar:2.5.1] at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.ifAvailable(DefaultListableBeanFactory.java:2035) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.h2Console(H2ConsoleAutoConfiguration.java:66) ~[spring-boot-autoconfigure-2.5.1.jar:2.5.1] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:638) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1334) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) ~[spring-beans-5.3.8.jar:5.3.8] at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:212) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:203) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:97) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:86) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:260) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:234) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:53) ~[spring-boot-2.5.1.jar:2.5.1] at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5161) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na] at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) ~[na:na] at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:829) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na] at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) ~[na:na] at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.core.StandardService.startInternal(StandardService.java:433) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.apache.catalina.startup.Tomcat.start(Tomcat.java:486) ~[tomcat-embed-core-9.0.46.jar:9.0.46] at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:123) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:104) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:450) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:199) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:182) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:160) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:577) ~[spring-context-5.3.8.jar:5.3.8] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.1.jar:2.5.1] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.1.jar:2.5.1] at jpabook.jpashop.JpashopApplication.main(JpashopApplication.java:11) ~[main/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na] at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.5.1.jar:2.5.1] Caused by: java.net.SocketTimeoutException: connect timed out at java.base/java.net.PlainSocketImpl.waitForConnect(Native Method) ~[na:na] at java.base/java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:107) ~[na:na] at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399) ~[na:na] at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242) ~[na:na] at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224) ~[na:na] at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:na] at java.base/java.net.Socket.connect(Socket.java:609) ~[na:na] at org.h2.util.NetUtils.createSocket(NetUtils.java:103) ~[h2-1.4.200.jar:1.4.200] at org.h2.util.NetUtils.createSocket(NetUtils.java:83) ~[h2-1.4.200.jar:1.4.200] at org.h2.engine.SessionRemote.initTransfer(SessionRemote.java:119) ~[h2-1.4.200.jar:1.4.200] at org.h2.engine.SessionRemote.connectServer(SessionRemote.java:435) ~[h2-1.4.200.jar:1.4.200] ... 84 common frames omitted 압축파일을 보내드립니다 구글드라이브 공유로 파일을 보냅니다 https://drive.google.com/drive/u/0/folders/1u0i3WD6stwer8BgSDa1UhIa65oUJJ2Ml h2 문제가 여러 원인으로 발생을 하는 것 같아요 명확한 정리가 필요할 듯 합니다. 영환님 모든 강의에서 h2를 사용을 하니 해결의 정확한 힌트가 필요합니다. 부탁드립니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
db를 설치하니 전혀 작동을 하지 않음
삭제된 글입니다
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
초기화가 안되요ㅜㅜ
안녕하세요! 강의를 다 듣고 복습하다가 다시 진행하려고 init 패키지를 지운 이후 컴파일 시 초기화가 되지 않습니다. 어떠한 insert 쿼리가 나가지 않습니다. 선생님의 강의자료를 복붙해도 똑같이 초기화가 진행되지 않습니다. 하지만 이전 프로젝트에서는 잘 돌아갑니다. 혹시 초기화 하는데 있어서 어떤 설정을 잘못한걸까여? package com.work.init;import com.work.flow.domain.*;import com.work.flow.domain.item.Book;import lombok.RequiredArgsConstructor;import org.springframework.stereotype.Component;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import javax.annotation.PostConstruct;import javax.persistence.EntityManager;@Component@RequiredArgsConstructorpublic class InitDb { private final InitService initService; @PostConstruct public void init() { initService.dbInit1(); initService.dbInit2(); } @Component @Transactional @RequiredArgsConstructor static class InitService { private final EntityManager em; public void dbInit1() { Member member = createMember("userA", "서울", "1", "1111"); em.persist(member); Book book1 = createBook("JPA1 BOOK", 10000, 100); em.persist(book1); Book book2 = createBook("JPA2 BOOK", 20000, 100); em.persist(book2); OrderItem orderItem1 = OrderItem.createOrderItem(book1, 10000, 1); OrderItem orderItem2 = OrderItem.createOrderItem(book2, 20000, 2); Order order = Order.createOrder(member, createDelivery(member), orderItem1, orderItem2); em.persist(order); } public void dbInit2() { Member member = createMember("userB", "진주", "2", "2222"); em.persist(member); Book book1 = createBook("SPRING1 BOOK", 20000, 200); em.persist(book1); Book book2 = createBook("SPRING2 BOOK", 40000, 300); em.persist(book2); Delivery delivery = createDelivery(member); OrderItem orderItem1 = OrderItem.createOrderItem(book1, 20000, 3); OrderItem orderItem2 = OrderItem.createOrderItem(book2, 40000, 4); Order order = Order.createOrder(member, delivery, orderItem1, orderItem2); em.persist(order); } private Member createMember(String name, String city, String street, String zipcode) { Member member = new Member(); member.setName(name); member.setAddress(new Address(city, street, zipcode)); return member; } private Book createBook(String name, int price, int stockQuantity) { Book book = new Book(); book.setName(name); book.setPrice(price); book.setStockQuantity(stockQuantity); return book; } private Delivery createDelivery(Member member) { Delivery delivery = new Delivery(); delivery.setAddress(member.getAddress()); return delivery; } }} 위의 코드는 강의자료의 코드들입니다.
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
수업 코드는 아니지만 페이징 최적화에 대해
안녕하세요 강사님 강의를 수강하면서 따로 토이 프로젝트를 만들어보고있는데 페이징 부분에 대해서 성능 최적화를 어떻게 해야 좋을지 모르겠어서 죄송하게도 강의 내용은 아니지만 질문드려봅니다 public class Board { ..// @OneToMany(mappedBy = "board", cascade = CascadeType.ALL) private Set<Comment> comments = new LinkedHashSet<>(); @OneToMany(mappedBy = "board", cascade = CascadeType.ALL) private Set<BoardAlbum> boardAlbums = new LinkedHashSet<>(); @ManyToOne(fetch = FetchType.LAZY) private Member member; 제 Board Entity 코드고 수강하면서 조회 성능의 개선을 위해서 ToOne은 Entity Graph로, To Many는 BatchSize 1000을 통한 최적화로 조회 성능을 향상시킬 수 있었는데 페이징의 경우 Desc 를 사용함으로써 속도가 매우 느려짐을 확인했습니다 @Query("SELECT b FROM Board b where b.id<:id order by b.id desc ") @EntityGraph(attributePaths = {"member"}) Slice<Board> findBoards(Pageable pageable, @Param("id") Long id); Board 데이터 백만개 기준으로 위의 로직은제일 자주 보이는 첫 페이지가 평균 2초 ~ 마지막 페이지 거의 0초의 속도로 데이터를 조회합니다.. 좀 더 개선해보고자 인덱스는 pk가 인덱스기에 pk로 정하고 no offset으로,Querydsl을 사용해 public List<~dto> paginationNoOffset(Long boardId, int size) { return queryFactory .select(Projections.fields(~ dto)) .from(board) .join(board.member,member).fetchJoin() .where( ltBoardId(boardId), ) .orderBy(board.id.desc()) .limit(size) .fetch(); } private BooleanExpression letBoardId(Long boardId) { if (boardId == null) { return null; } return board.id.lt(boardId); } 위와 같이 구성해 테스트해보았으나 오히려 더 느린 4초대가 나오더라구요 강의에 대한 질문은 아니지만 혹시 해답에 대한 언질을 주실 수 있으시다면 감사하겠습니다
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
orderItem LAZY 로딩 질문
안녕하세요. orderItems.stream().forEach(o -> o.getItem().getName()); orderItem 반복문 돌 때 getName을 하거나 getprice, getstockQuantity를 넣어도 모든 필드가 로딩이 되는데 왜 그런건지 이해가 잘 안가는데 간단한 설명 부탁드려도 될까요?
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
qeuryDSL에 .where() 안에 쓰이는 조건들에 대해서 궁금한게 있습니다..!
안녕하세요 강사님. 강의를 듣다보니 궁금한게 있어서 질문드립니다..! queryDSL의 장점 중에 '코드 재사용'이 있었는데 statusEq 나 nameLike 같은 where 안에 들어가는 조건들은 실무에선 별도의 '조건 인터페이스'??? '조건 Repository'??? ( 워딩이 이상하네요 .. 허허 ) 같은걸로 따로 두시는지요 ..? 가령 이런 식으로 필요한 조건들을 담은 별도의 저장소를 쓰시는지 궁금합니다..!
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
count 변수로 조회된 데이터 숫자를 세는 부분
안녕하세요, 영한님 강의를 듣다가 궁금한 부분을 질문드립니다! return new Result(collect.size(), collect); static class Result<T>{ private int count; private T data; } -> count값은 강의에서 4 위와 같은 조회 부분에서 Dto 클래스인 Result에 count 변수를 선언하면 collect.size()로 바로 연결이 됨을 볼 수 있었는데, 이는 2개의 파라미터가 순서대로 적용되어 Result라는 객체가 생성되어서 그렇다고 이해하면 되는지 궁금합니다. 너무 기초적인 질문 같은데 초보라서 그렇다고 너그럽게 이해 부탁드립니다. 항상 감사합니다..
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
html에서 DTO에담긴 객체형식이 전송가능할까요?
안녕하세요? 강의 잘 듣고있습니다. html에서 DTO에담긴 객체형식이 전송가능할까요? String city, street, zipcode가 포함된 객체 Address를 담은 회원등록DTO를 이용해서 회원등록기능을 만들고있는데요, html에선 form.address.city, form.address.street이런식으로 , 위치를 지정하면 될거라 생각하였는데, Strin이나 int 등은 값이 잘 저장되는데, address에 속한 값들은 자바에선 null로만 받아져요. 반대로 조회할때는 form.address.city, form.address.street를 이용하니 문제없이 조회가 되었습니다. 즉 자바에서 html로는 DTO안의 객체형식이 제대로 전송되는데, html에서 자바로는 DTO의 객체형식이 전송이 안되는 상태인데, 애초에 등록페이지에 모델로 해당 DTO를 form으로 전송시켜놓았고, 그래서 form.address.city으로 위치를 지정해서 값을 저장하면 문제없이 될거라 생각했는데, 어디서 잘못된걸까요? 관련코드입니다. DB 1,2행은 수동으로 추가하였습니다 DTO public class CompanyDTO { private Long id; private String name; private Address address; Controller @GetMapping("register")public String companyRegister(Model model) { model.addAttribute("form", new CompanyDTO()); return "company/register";}@PostMapping("register")public String companyRegister2(CompanyDTO companyDTO) { companyService.saveCompany(companyDTO); return "redirect:/company/list";} @GetMapping("list")public String companyList(Model model) { List<Company> companyList = companyService.findAll(); List<CompanyDTO> companyDTOList = companyService.transDTOList(companyList); model.addAttribute("company_list", companyDTOList); return "company/list";} html register(등록부분) > 이 부분이 안됩니다! <form th:action="@{register}" th:object="${form}" method="post"> <div class="form-group"> <label th:for="name">회사명</label> <input type="text" th:field="*{name}" class="form-control" placeholder="이름을 입력하세요"> </div> <div class="form-group"> <label th:for="city">도시</label> <input type="text" th:field="*{address.city}" class="form-control" placeholder="주소를 입력하세요"> </div> html list(조회부분) > 정상동작합니다 <tr th:each="company : ${company_list}"> <td th:text="${company.id}"></td> <td th:text="${company.name}"></td> <td th:text="${company.address.city}"></td> 감사합니다
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
v2 api의 delivery 쿼리 조회문
안녕하세요 영한님! 간단한 주문 조회v2 질문이 있습니다. @GetMapping("/api/v2/simple-orders")public Result ordersV2() { List<Order> orders = orderService.findAll(new OrderSearch());//프록시가 들어있는 orde 객체 List<SimpleOrderDto> collect = orders.stream().map(o -> new SimpleOrderDto(o.getId(), o.getMember().getName(), o.getOrderDate(), o.getStatus(), o.getDelivery().getAddress())). collect(Collectors.toList()); return new Result(collect);} 위의 v2 api를 실행하면 문제없이 5개의 쿼리문이 나가는 것을 확인했습니다. name을 조회하는 쿼리는 예상했던데로 단순 조회 쿼리인 select member0_.member_id as member_i1_5_0_, member0_.city as city2_5_0_, member0_.street as street3_5_0_, member0_.zipcode as zipcode4_5_0_, member0_.name as name5_5_0_ from member member0_ where member0_.member_id=? 와 같이 나가지만. delivery 엔티티에 접근할때 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_, order1_.orders_id as orders_i1_6_1_, order1_.delivery_id as delivery4_6_1_, order1_.member_id as member_i5_6_1_, order1_.order_date as order_da2_6_1_, order1_.status as status3_6_1_ from delivery delivery0_ left outer join orders order1_ on delivery0_.delivery_id=order1_.delivery_id where delivery0_.delivery_id=? 위와 같이 외부 조인문이 나가는 것을 확인했습니다. 마치 패치조인을 한거 같은 전혀 예상치 못한 쿼리문이여서 질문을 드립니다. 또한 모두 lazy로 설정을 했습니다. 혹시 데이터베이스의 방언차이 때문일까요? mysql 사용중입니다.
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
트랜잭션
안녕하세요 영한님! 트랜잭션 범위에 질문이 있습니다. @PutMapping("/api/v2/members/{id}")public UpdateMemberResponse updateMemberV2(@PathVariable Long id, @Valid @RequestBody UpdateMemberRequest request) { memberService.update(id, request.getName()); Member member = memberService.findOne(id); return new UpdateMemberResponse(id, member.getName());} 위와 같이 코드를 작성 후 수정을 진행하게 되면 서비스 계층의 update 메서드를 통해 두번의 sql문인 select, update 쿼리가 나가는 것을 확인 했습니다. 하지만 밑의 findOne 메서드를 통해 조회를 할 때 조회 sql문이 나가지 않는 것을 확인했습니다. 제가 알고 있는 바로는 트랜잭션이 다르기 때문에 데이터베이스에서 조회 후 영속성 컨텍스트에 저장하는걸로 알고 있습니다. 그래서 제가 잘못 이해하고 있나 질문드립니다. 또한 Member member = memberService.findOne(id); 에서 member 객체는 준영속 상태인가요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
회원 수정 API id, name 값 받을 때
데이터 안에 id, name 을 같이 받는게 아니라, 굳이 id 는 url 을 통해, name 은 데이터를 통해 받는 이유가 있을까요?
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
@Transactional 어노테이션 질문드립니다
안녕하세요 영한님 Jpa 로 단순 조회기능을 이용하게될때 Service Layer 에서 @Transactional(readOnly=true) 를 메소드에 선언해서 사용했었는데요 테스트하다보니 @Transactional 어노테이션 없이 사용해도 조회도되고 controller 단에서도 영속성컨텍스트가 살아있는걸로 확인이 되었습니다 (osiv 는 켜놓았습니다) findById or findAll 같은 단순 조회기능에서는 @Transactional 은 없어도 되는건가요? spring 에서는 기본적으로 트랜잭션범위와 영속성컨텍스트의 범위가 동일하다고 알고있는데 @Transactional 설정을 안해줘도 조회기능에선 영속성컨텍스트가 유지된다고 보면될까요 ? 아니면 @Transactional(readOnly=true) 는 @Transactional 없이 동작하는것과 어떤 차이가 있는걸까요 ㅠㅠ
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
도메인 엔티티의 @Setter 질문입니다
안녕하세요 김영한 선생님! 강의를 듣던 중 이전 강의들에서 되도록이면 엔티티에 @Setter는 사용하는 것은 지양하는것이 좋다고 말씀하셨던게 기억에 남는데 현재 강의인 수정 부분에서 memberService 에 코드를 보면 member.set**() 을 사용하는것에 의문이 들어 질문 드립니다. 혹시 실무에 가서 프로젝트를 하게 되면 위와 같은 방식으로 update 시에 setter를 사용해도 되는건가요? 만약 사용하지 않는게 좋다면 어떠한 방식으로 유도하는게 좋을지 질문 드립니다!
- 미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
프록시 질문있어요 ㅠㅠ
강의 [06:10] Order의 멤버 필드 Member 엔티티는 LAZY 타입이라서 프록시 객체가 주입되고, 프록시 객체는 빈(깡통) 객체인데 어떻게 멤버 엔티티를 참조해서 무한루프에 빠지는건가요? ㅠㅠ 혹시 member.getName() 으로 초기화 하지 않아도, jackson이 필요로 할 때 프록시 객체가 초기화 되는건가요??
- 해결됨실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
강의중에 실무에 대한 궁금중이 있어서 질문합니다.
강의중에서 SimpleOrderDto 클래스 생성자에 인자로 entity를 받는데 중요하지 않은곳에서 중요한것을 받는건 상관 없다고 하셨는데..! 영한님도 실무에서 dto 생성자에 entity를 직접 받아서 사용하시나요??? 될수있으면 엔티티로 받지 말고 값을로 받아서 채우던가 , 다른 클래스(dto) 변환 해서 넘기는게 좋다는 이야기를 들은적이 있어서요 예를들어 public class CommonWrapper { @Getter public static class SelectMember { private Long id; private String writer; private String contents; private String mention; private SelectMember(Long id, String writer, String contents, String mention) { this.id = id; this.writer = writer; this.contents = contents; this.mention = mention; } public static SelectMember from (Member member) { return new SelectMember(member.getId(), member.getWriter(), member.getContents(),member.getMention()); } } 궁금해서 여쭈어봅니다!!