25%
66,000원
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! 스프링 데이터 JPA
team 조회시 query 관련
영한님 log와 달리, 제가 조회를 했을때는 hibernate가 for문에서 해당 팀을 조회 하는 순서에 따라 select쿼리를 날려서 데이터를 db에서 가져온 후 print해주는데요 영한님 로그에서는 미리 team1,2 를 다 조회하고 그 다음에 출력해주는것으로 보입니다. (여기서 이미 조회해서 영속성 컨텐츠로 만든 것들은 다시 select 쿼리를 날리진 알고요 team 1, 2 의 경우 1번씩만 날림) em.clear해서 캐시를 초기화 했기 때문에, getTeam을 하였을 때, 아래의 결과 처럼 getTeam으로 조회 하려고 할때, hibernate가 select 쿼리를 날리는게 맞다고 보는데 영한님 로그에서는 어떻게 hibernate가 미리 2개를 다 조회할 것을 알고 select문을 먼저 2번 날린 것인지 궁금합니다. System.out.println("============");for(Member member:members){ System.out.println(member); System.out.println(member.getTeam());}System.out.println("============"); ============ Member(id=3, username=member1, age=10) 2021-07-30 05:38:40.449 DEBUG 1508 --- [ main] org.hibernate.SQL : select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=? 2021-07-30 05:38:40.451 INFO 1508 --- [ main] p6spy : #1627591120451 | took 0ms | statement | connection 3| url jdbc:h2:tcp://localhost/~/lecture_datajpa select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=? select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=1; Team(id=1, name=teamA) Member(id=4, username=member2, age=10) Team(id=1, name=teamA) Member(id=5, username=member3, age=10) 2021-07-30 05:38:40.460 DEBUG 1508 --- [ main] org.hibernate.SQL : select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=? 2021-07-30 05:38:40.461 INFO 1508 --- [ main] p6spy : #1627591120461 | took 0ms | statement | connection 3| url jdbc:h2:tcp://localhost/~/lecture_datajpa select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=? select team0_.team_id as team_id1_1_0_, team0_.name as name2_1_0_ from team team0_ where team0_.team_id=2; Team(id=2, name=teamB) Member(id=6, username=member4, age=10) Team(id=2, name=teamB) ============
- 미해결실전! 스프링 데이터 JPA
Query관련으로 질문이 있습니다 !!
위와같이 Product, Restaurant 두개의 엔티티를 만들었는데 Product엔티티자체가 Restaurant엔티티에 포함된다고 생각해서 Product엔티티의 삭제 및 생성의 관해선 Restaurant이 관할해야한다고 생각해 cascade와 Repository도 Restaurant만 만들었는데요 이러한 방식이 괜찮을까요 ? 정리하면 1.Restaurant를 애그리거트 루트로 보고 Product에 접근하기위해선 항상 Restaurant을 거쳐야된다고 생각해 위와같은 구조로 만들었습니다 괜찮을까요 ? 2. (실제 테스트는 해보지않은 부분이라 틀릴 수 있습니다 ㅠㅠ 의미만 봐주세요 ) 1번에서 이어지는 부분인데 RestaurantRepository에서 Product의 Id를통해 Restaurant엔티티를 가져오는 부분입니다 이러한 코드는 어떻게 생각하시나요 ? - Restaurant엔티티를 통해 Product에 접근해야된다고 생각해서 ProductRepository를 만들지 않았습니다 - 그렇기때문에 1:N 중 1쪽에서 탐색하고있는데 괜찮을까요 ?
- 미해결실전! 스프링 데이터 JPA
질문있습니다.
안녕하세요 insert 벌크 쿼리에 관해 질문있습니다. 강의에서 말씀해주신 대로 해보니 delete와 update의 경우 한번에 처리되는 것을 확인할 수 있었습니다. 문제는 Insert 였습니다. 저는 MySQL 를 사용하면서 IDENTITY 전략을 사용해왔었는데 MySQL의 경우 벌크 INSERT 쿼리를 날리기 위해서는 찾아보니 Batch Insert를 사용하기 위해서는 IDENTITY 전략이 아니라 TABLE 전략을 사용해야 한다고 하더라구요. 제가 궁금한 점은 아래와 같습니다. 1. 다른 ENTITY들은 IDENTITY 전략을 사용하고 Batch Insert가 필요한 특정 ENTITY만 TABLE 전략으로 변경해도 괜찮을까요? 2. 실무에서는 INSERT 쿼리를 한 번에 날리기 위해서는 어떤 방식을 사용하나요?? 감사합니다 :) 2.
- 미해결실전! 스프링 데이터 JPA
질문있습니다.
안녕하세요! 오랜만에 다시 보다가 갑자기 궁금한 부분이 생겨서 질문드립니다! 1. JpaRepository를 이용하면 simpleJpaRepository를 사용하게 되는 것으로 기본적으로 @Transactioanal(readOnly=true)와 @Repository를 달고 있는 것으로 생각하면 될까요? 2. 저는 서비스 계층에서만 @Transactional을 붙여서 사용하고 있는데 구글링하다보니 Repository 계층에서도 @Transactional을 사용하는 경우가 존재하던데 Repository에서 @Transactional을 사용하는 경우는 어떨 때 사용하는 것인가요?
- 미해결실전! 스프링 데이터 JPA
totalCount는 어디서 쓰이나요?
페이징하면 제일 먼저 생각나는게 영한님이 말씀하신것 처럼 게시판의 페이징 기능이 생각이 납니다. Member가 m1~m5까지 있을때 이름, 나이 m1 AAA 10 m2 BBB 10 m3 CCC 10 m4 DDD 10 m5 EEE 10 이렇게 나이는 동일하고 이름만 다른 조건이 있다고 했을 경우 강의에서 offset과 limit을 활용하여 3개씩 잘라서 1 page = m1,m2,m3 2page = m4,m5 이렇게 나누는것 까지는 잘 이해가 됐습니다. 하지만 이때 totalCount는 강의내용을 참고하면 age가 같은 사람의 개수이니 5 라는 숫자가 나오게 되는데요 이 totalCount는 어디서 쓰이는건가요? 제가 생각하는 페이징에는 offset과 limit만 있어도 게시글 다음페이지 이런걸 할 수 있을거 같은데 어디서 쓰이는지 궁금합니다 ㅎㅎ
- 해결됨실전! 스프링 데이터 JPA
mybatis랑 jpa의 차이가 궁금합니다
안녕하세요 강사님. 3개월쯤 된 신입 개발자 입니다. 회사에서 myBatis를 사용한 프로젝트를 진행했고, 최근 한가해진 참에 JPA도 배워보고 싶어서 강의를 듣게되었는데 아무리 생각해도 JPA가 주는 CRUD의 장점을 myBatis가 커버할 수가 없을 것 같습니다. 1. 혹시 실무에서 JPA 대신 myBatis를 사용하는 특별한 이유가 있을까요? 2. 두 개를 섞어서 사용(JPA기반 동적쿼리만 myBatis 사용) 하면 좋을거같은데 실제 실무에서 이런 방식으로 사용하는 경우가 있을까요?
- 미해결실전! 스프링 데이터 JPA
@CreationTimestamp와 @CreatedDate의 선택
저는 평소에 실무에서 @CreationTimestamp를 썼는데요. 이게 하이버네이트에서 제공하는 건줄도 모르고 그냥 막 사용했는데, 이번에 영한님 강의에서 @CreatedDate를 알게되어 둘을 비교해보니 @CreationTimestamp 는 하이버네이트 제공 @CreatedDate 는 스프링 프레임워크 제공 인 것 같더라고요 @CreationTimestamp는 JPA의 표준이 아니라 하이버네이트에서 제공하는 거라 아무래도 나중에 그럴일은 없겠지만, JPA 구현체를 하이버네이트 말고 딴거로 바꾸면 못쓴다는 단점이 있을 것 같긴 한데, @CreationTimestamp를 쓰면 @EnableJpaAuditing 같은거 안 해줘도 돼서 편하더라고요. 실무에서는 어떤 방식이 더 선호되나요?
- 미해결실전! 스프링 데이터 JPA
JPA 테스트코드 작성시 DDL 관련 질문있습니다
안녕하세요? 현재 프로젝트에 테이블이 약 400여개가 있습니다. 엔티티 개수도 그에 비례하구요. 문제는 이렇습니다. 임베디드 디비로 테스트 코드를 돌리는데요, Member 엔티티에 대한 테스트 코드를 작성하고 테스트 코드를 실행시키면 400여개의 엔티티에 대한 DDL이 모두 실행된 후 Member 엔티티에 대한 테스트코드가 실행됩니다. 유닛 테스트시 Member 엔티티에 대한 DDL만 생성되어 관련된 테이블 몇개만 생성한 후 간단하게 돌려보고 싶은데 제가 찾아서 시도해본 것으로는 @EntityScan으로 엔티티 스캔범위를 좁히거나 scheme.sql을 매번 작성하는 것, @DataJpaTest의 필터를 사용하는 것 등입니다. @DataJpaTest(includeFilters = {@ComponentScan.Filter(classes = Member.class)}) @Import(TestQueryDslConfig.class) class MemberRepositoryTest {} 특정 엔티티 클래스 몇개만 딱 찝어서 할수있는 방법이 있을 것 같은데 생각보다 솔루션이 안찾아집니다. 혹시 도움을 받을 수 있을까요?
- 미해결실전! 스프링 데이터 JPA
SQLGrammarException 발생 ...
안녕하세요 ... 정말 재밌고 알차게 강의를 들었는데요.. ! 마지막 강의의 native Projection 을 구현할때 ... SQLGrammarException 이발생합니다 ㅜㅜ userName은 제가 entity를 만들때 userName으로 만들었어요..! 이유를 잘모르겠습니다 ..! 도와주세요 ! 감사합니다 :)
- 미해결실전! 스프링 데이터 JPA
postUpdate 어노테이션에 대하여
안녕하세요! JPA 정말 재미있게 잘 공부하고 있습니다. 제가 jpa를 사용해서 프로젝트를 하고 있는데, postUpdate annotation을 이용하여 특정 시점에 제가 원하는 작업을 하고 싶어서 그때 변화가 생기기 전의 entity와 변화가 생긴 후의 entity모두를 기록해야할 필요가 있어서요. 근데 postUpdate는 하나의 인자만(변경 후의 엔티티) 받는 것 같아서 이걸 어떻게 접근할 수 있을지 혹시 질문드릴 수 있을지 여쭤보게 되었습니다! 임시 방편으로는 postLoad가 되는 시점에 엔티티 내부에 transient 필드를 하나 선언하고 거기에 복사를 떠둔 후 postUpdate가 이뤄지는 시점에 이것을 읽어와 사용하는 방법을 생각해보았는데, 그러면 조회성 서비스 모두에서 postLoad가 불릴때 불필요하게 객체를 복사하는 문제가 생겨서요. 혹시 방법이 있을지 여쭤보고 싶습니다!! 감사합니다!
- 미해결실전! 스프링 데이터 JPA
하이버네이트 인터셉터문의
안녕하세요 강사님 다름아니라 하이버네이트 인터셉터 사용시 디비 인서트 업데이트 전후에 암호화가 필요한 필드 그리고 암호화가된 필드에 암호화나 복호화처리를 할 수 있는데 jpa에서 이런 인터셉터 스펙이 있는지 궁금합니다 구글링을 해도 하이버네이트 인터셉터는 있는데 jpa는 도저히 못 찾겠더라구요 그리고 없다면 하이버네이트 인터셉터를 사용해야하는지도 문의드립니다 답변주시면 감사드리겠습니다
- 해결됨실전! 스프링 데이터 JPA
Entity 사용에 대한 질문
안녕하세요. 강사님 먼저 항상 좋은 강의를 해주셔서 감사합니다. 제가 실무에서는 Mybatis만 사용하다, 강사님 강의를 통해서 처음 JPA를 접하고, 개인 프로젝트에서 처음 JPA를 사용하고 있습니다. 강의에서 Entity를 직접 반환을 하면 안된다고 하신걸로 기억을 하는데, API 개발 시 리턴을 할 때만 직접 Entity로만 반환을 하면 안되지는 일반 MVC 형태의 개발을 할 때는 직접 Entity를 반환하는 방식을 실무에서 사용을 하시는지 궁금합니다. 저는 평소 Controller에서 파라미터를 받을 때 @ModelAttribute를 이용해 DTO를 통해 파라미터를 받는 방식을 주로 이용하는데, JPA 사용 시 @ModelAttribute를 이용하여 직접 Entity를 받는 방식은 좋은 방식인지 궁금하여 질문 드립니다. 감사합니다.
- 미해결실전! 스프링 데이터 JPA
@Query를 사용하면 계속 확정적으로 오류가 뜹니다 왜 그런건지 도저히 모르겠네요..
spring jpa사용하지 않고 em.createquery를 사용해서 test를 실행 시켜도 무조건 에러가 뜹니다. 어디서 문제가 발생하는 걸까요? public interface OrderRepository extends JpaRepository<Order,Long> { List<Order> findByMarketAndTransactionPrice(String market,Double transactionPrice); @Query("select o from Order o") List<Order> findPlz(); List<Order> findByMarketAndTransactionPriceAndTradeStatusAndStatus(String market, Double transactionPrice, OrderTradeStatus tradeStatus, OrderStatus status);} @Testpublic void errorTest() throws Exception { //given orderRepository.findPlz(); //when //then} ; 2021-06-15 03:03:55.491 INFO 17208 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@31edaa7d testClass = OrderRepositoryTest, testInstance = com.gon.coin.demotradingcoin.repository.OrderRepositoryTest@19c578bf, testMethod = errorTest@OrderRepositoryTest, testException = org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [select order0_.order_id as order_id1_5_, order0_.created_date as created_2_5_, order0_.excution_time as excution3_5_, order0_.market as market4_5_, order0_.member_id as member_i9_5_, order0_.status as status5_5_, order0_.trade_status as trade_st6_5_, order0_.trading_volume as trading_7_5_, order0_.transaction_price as transact8_5_ from order order0_]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement, mergedContextConfiguration = [WebMergedContextConfiguration@26adfd2d testClass = OrderRepositoryTest, locations = '{}', classes = '{class com.gon.coin.demotradingcoin.DemoTradingCoinApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@5656be13, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@71d44a3, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@34123d65, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@4afcd809], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]] org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [select order0_.order_id as order_id1_5_, order0_.created_date as created_2_5_, order0_.excution_time as excution3_5_, order0_.market as market4_5_, order0_.member_id as member_i9_5_, order0_.status as status5_5_, order0_.trade_status as trade_st6_5_, order0_.trading_volume as trading_7_5_, order0_.transaction_price as transact8_5_ from order order0_]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:279) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:144) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$ExposeRepositoryInvocationInterceptor.invoke(CrudMethodMetadataPostProcessor.java:364) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) at com.sun.proxy.$Proxy133.findPlz(Unknown Source) at com.gon.coin.demotradingcoin.repository.OrderRepositoryTest.errorTest(OrderRepositoryTest.java:103) 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.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54) Caused by: org.hibernate.exception.SQLGrammarException: could not prepare statement at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:182) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:148) at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1984) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1914) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1892) at org.hibernate.loader.Loader.doQuery(Loader.java:937) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:340) at org.hibernate.loader.Loader.doList(Loader.java:2689) at org.hibernate.loader.Loader.doList(Loader.java:2672) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2506) at org.hibernate.loader.Loader.list(Loader.java:2501) at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:504) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:395) at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:220) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1508) at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1537) at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1505) at org.hibernate.query.Query.getResultList(Query.java:132) at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:129) at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91) at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:136) at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:125) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ... 42 more Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "SELECT ORDER0_.ORDER_ID AS ORDER_ID1_5_, ORDER0_.CREATED_DATE AS CREATED_2_5_, ORDER0_.EXCUTION_TIME AS EXCUTION3_5_, ORDER0_.MARKET AS MARKET4_5_, ORDER0_.MEMBER_ID AS MEMBER_I9_5_, ORDER0_.STATUS AS STATUS5_5_, ORDER0_.TRADE_STATUS AS TRADE_ST6_5_, ORDER0_.TRADING_VOLUME AS TRADING_7_5_, ORDER0_.TRANSACTION_PRICE AS TRANSACT8_5_ FROM ORDER[*] ORDER0_ "; expected "identifier"; SQL statement: select order0_.order_id as order_id1_5_, order0_.created_date as created_2_5_, order0_.excution_time as excution3_5_, order0_.market as market4_5_, order0_.member_id as member_i9_5_, order0_.status as status5_5_, order0_.trade_status as trade_st6_5_, order0_.trading_volume as trading_7_5_, order0_.transaction_price as transact8_5_ from order order0_ [42001-199] at org.h2.message.DbException.getJdbcSQLException(DbException.java:451) at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) at org.h2.message.DbException.getSyntaxError(DbException.java:243) at org.h2.command.Parser.readColumnIdentifier(Parser.java:4530) at org.h2.command.Parser.readIdentifierWithSchema(Parser.java:4491) at org.h2.command.Parser.readTableFilter(Parser.java:1853) at org.h2.command.Parser.parseSelectSimpleFromPart(Parser.java:2641) at org.h2.command.Parser.parseSelectSimple(Parser.java:2788) at org.h2.command.Parser.parseSelectSub(Parser.java:2636) at org.h2.command.Parser.parseSelectUnion(Parser.java:2469) at org.h2.command.Parser.parseSelect(Parser.java:2440) at org.h2.command.Parser.parsePrepared(Parser.java:814) at org.h2.command.Parser.parse(Parser.java:788) at org.h2.command.Parser.parse(Parser.java:760) at org.h2.command.Parser.prepareCommand(Parser.java:683) at org.h2.engine.Session.prepareLocal(Session.java:627) at org.h2.server.TcpServerThread.process(TcpServerThread.java:270) at org.h2.server.TcpServerThread.run(TcpServerThread.java:175) at java.base/java.lang.Thread.run(Thread.java:831) at org.h2.message.DbException.getJdbcSQLException(DbException.java:451) at org.h2.engine.SessionRemote.done(SessionRemote.java:607) at org.h2.command.CommandRemote.prepare(CommandRemote.java:85) at org.h2.command.CommandRemote.<init>(CommandRemote.java:51) at org.h2.engine.SessionRemote.prepareCommand(SessionRemote.java:477) at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1292) at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:77) at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:349) at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:311) at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java) at com.p6spy.engine.wrapper.ConnectionWrapper.prepareStatement(ConnectionWrapper.java:118) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:146) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:172) ... 73 more
- 미해결실전! 스프링 데이터 JPA
JPA 에서 행 연산 방법 질문입니다
안녕하세요 JPA 로드맵을 따라 JPA를 공부하고 있는 수강자 입니다. 만약 테이블에 상품명, 상품 수량, 상품 단가 가 있고 이를 출력할때는 상품명, 상품 수량, 상품 단가, (수량 * 단가 ) as 비용 ...; 이런식으로 데이터 행의 다른 컬럼의 값을 연산해서 출력 한다거나 조건문에 넣을수 있는 방법이 JPA에 있나요? 아니면 네이티브 쿼리나 마이바티스 같이 SQL 자체를 직접 작성해야 하는지 궁금합니다.
- 미해결실전! 스프링 데이터 JPA
Thread 처리 관련 질문이 있습니다
@Entity@Getterpublic class Member { @Id @GeneratedValue private Long id;} @SpringBootTest@Rollback(value = false)class MemberRepositoryTest { @Autowired MemberRepository memberRepository; @BeforeEach void prepareData() { memberRepository.save(new Member()); } @Test @Transactional void findMember() throws InterruptedException { Member findMember = memberRepository.findAll().get(0);// Optional<Member> newFindMember = memberRepository.findById(findMember.getId());// System.out.println("newFindMember.isEmpty() = " + newFindMember.isEmpty()); int threadCount = 1; int latchCount = 1; ExecutorService service = Executors.newFixedThreadPool(threadCount); CountDownLatch countDownLatch = new CountDownLatch(latchCount); for(int i = 0; i < latchCount; i++) { service.execute(() -> { Optional<Member> newFindMember = memberRepository.findById(findMember.getId()); System.out.println("newFindMember.isEmpty() = " + newFindMember.isEmpty()); countDownLatch.countDown(); }); } countDownLatch.await(); }} 위에 처럼 테스트 전에 BeforEach 에서 Member 1건을 생성하고 Thread 환경이라는 전제 하에서 가져오는 부분을 샘플로 짰는데요, 위 코드를 실행하면 궁금한 부분이 2가지 있습니다. 1. findById 를 할 경우 select 쿼리가 실행됩니다. @Transactional 로 선언되어 최초 findAll 에서 가져온 객체들이 영속성 컨텍스트에 남아있을테니 findById 시점에는 영속성컨텍스트의 대상을 가져올 것 같은데 왜 select 쿼리가 실행되는 건가요? 2. findById 를 통해 가져온 대상이 빈객체 입니다. isEmpty 가 true 로 나오는데요, 어찌됐건 DB에서 조회를 해왔을테니 대상을 정상적으로 가져와야 할 것 같은데, 왜 아무것도 가져오지 못하는 건가요? @Transactional 어노테이션을 제거하면 정상적으로 가져 옵니다. Thread 환경이 아닌 일반적인 코드에서는 예상대로 잘 실행이 되는데 Thread 환경에서는 왜 그런지 모르겠네요ㅠ
- 해결됨실전! 스프링 데이터 JPA
실습 프로젝트 배포판(jar) 빌드 및 실행시 트러블
안녕하세요. 영한님. Spring Data JPA 강의를 모두 마쳤고, Query DSL 강의 들은 후 다른 강의들과 함께 다시 들어 볼 계획입니다. 질문은 : 정상적으로 실행되는 Spring Boot 프로젝트를 배포용 jar로 만들어, 커맨드 창에서 실행하면 에러가 발생하는 상황인데 이럴 때 어느 부분을 체크해야 합니까? 자료 1 : 해당 프로젝트 다운로드 (zip) : https://we.tl/t-qsuxCwz4rf이 zip 파일은 영한님의 Spring Data JPA 강의를 끝까지 따라 한 프로젝트입니다. 물론 강의에서의 코드와 완전히 똑같지는 않습니다. 예를 들면 DB는 MySQL을 사용합니다. 제가 배포용 artifact를 설정하고 jar 빌드 후 커맨드 창에서 실행하는 동영상 : https://youtu.be/hAlztOYw9uA 감사합니다.
- 미해결실전! 스프링 데이터 JPA
findById 반환타입 Optional
안녕하세요 선생님. 좋은 강의 매번 감사합니다! 강의를 듣고 토이프로젝트중에 질문이 생겼습니다! 강의 21분쯤에 스프링 데이터 JPA가 제공하는 findById의 반환값을 받아올때 반환값이 없을 수도 있기 때문에 Optional이고 강의에선 편의상 get()으로 가져온다고 하셨습니다! 강의에서 orElse 로 처리한다고 간단하게 언급해주셨는데, 실무에서는 그럼 위와 같은 상황에서 어떤식으로 가져오나요? 관련되어서 조사를 해보았는데 orElse로 값이 없을때 반환할 값을 넣어준다고 하더라구요. 그럼 이 테스트에서는 값이 없을때 반환할 객체 하나 생성해두고 orElse에 넣으면 되는건가요?
- 미해결실전! 스프링 데이터 JPA
서버가 여러대일때 createdDate, updatedDate 처리?
안녕하세요. 보통 createdDate 나 updatedDate 같은걸 등록할때 서버쪽에서 시간을 얻어서 등록하나요? 만약 서버가 여러개 있다고 할때 각 서버마다 아주 미세하게 시간이 다를수도 있을거 같은데요. 그럼 실제 A서버에서 등록한 시간이 B서버에서 등록한 시간보다 느린데 빠르게 등록될수도 있을거같아서요. 차라리 db에서 제공하는 default값이나 트리거등으로 값을 넣어주는게 확실하고 더 낳지 않나요? 실무에선 보통 어떻게 처리하는지 궁금합니다. 1. 외부타임서버에서 가져오는건 시간 텀이 있을수 있으니 내부에 NTP서버를 두고 시간갱신을 한다. 이떄 NTP클라이언트들의 시간갱신을 텀을 보통 얼마나 주는지도 궁금합니다. 24시간씩 두지는 않을거 같고 6시간? 1시간? 10분? 2. 시간이 중요할거 같으면 db에서 처리한다. 그리고 시간업데이트할떄 연관된 엔티티끼리의 createdDate 시간은 같이 맞추나요? 아님 조금 차이가 나둬 상관없으니 각각 시간을 구해서 업데이트하나요? 아님딱히 중요한건 아니니 그냥 개별로 업데이트 하나요? 예를들어 ORDER, ORDER_ITEM, DELIVERY, ORDER_HISTORY(ORDER와 N:1의 crud내역) 엔티티가 있을때 같은 주문일경우 각각의 엔티티의 시간을 똑같이 맞추나요? 아님 시간차이가 조금 나도 상관없으니 그냥 엔티티별로 createdDate, updatedDate를 업데이트하나요? 그리고 새 강의 계획은 언제쯤 인지 알수 있을까요?
- 해결됨실전! 스프링 데이터 JPA
Auditing 관련 질문 입니다
글을 조회하면 조회수가 1 올라가도록 서비스를 짰는데, 문제는 조회수를 올리면서 lastModifiedDate 필드도 함께 업데이트 됩니다. 제가 원하는 동작은 글 작성자가 글을 수정했을 때만 lastModifiedDate 필드가 업데이트되는 것입니다. 이 경우에는 상속을 하지 않고 lastModifiedDate 필드를 따로 만들어 수정 메소드에서 lastModifiedDate 필드를 수정하는게 best practice 일까요? 감사합니다. @MappedSuperclass@Getter@EntityListeners(AuditingEntityListener.class)public class BaseEntity { @CreatedDate private LocalDateTime createdDate; @LastModifiedDate private LocalDateTime lastModifiedDate; public boolean isModified() { return !createdDate.isEqual(lastModifiedDate); }} @Entity@Getter@NoArgsConstructor(access = AccessLevel.PROTECTED)public class Post extends BaseEntity { @Id @GeneratedValue @Column(name = "post_id") private Long id; @ManyToOne(fetch = LAZY) @JoinColumn(name = "member_id") private Member member; private int views; private String title; @Column(length = 2000) private String content; public Post(Member member, String title, String content) { this.member = member; this.title = title; this.content = content; } public void increaseViews() { views += 1; }} @Service@RequiredArgsConstructor@Transactionalpublic class PostService { private final PostRepository postRepository; public Post write(Post post) { return postRepository.save(post); } @Transactional(readOnly = true) public Page<Post> findAll(Pageable pageable) { return postRepository.findAll(pageable); } public Post view(Long id) throws PostNotFoundException { Post post = postRepository.findById(id).orElseThrow(() -> new PostNotFoundException("게시물을 찾을 수 없습니다.")); post.increaseViews(); return post; }} public interface PostRepository extends JpaRepository<Post, Long> { @Override @EntityGraph(attributePaths = {"member"}) Page<Post> findAll(Pageable pageable);}
- 미해결실전! 스프링 데이터 JPA
LAZY 로딩과 Transactional 에 대해 질문드립니다.
안녕하세요 강사님 강의 열심히 수강하고 있습니다 ~~ 질문은 Lazy 로딩은 사용시점에 쿼리가 발생하니까 처음 쿼리 발생 이후 뒷쪽 로직에 LAZY 로딩이 필요한경우 꽤 Transactional 범위가 넓어지더라구요 그래서 Transactional 범위 사이에 update나 insert 있는 경우는 @Transactional(propagation = Propagation.REQUIRES_NEW) 보통 요걸로 처리하고 있는데 이렇게 Transcational을 길게 가져갈 경우혹시 성능 이슈나 다른 문제사항이 있을까요? ( PS. 다른 방법으로 생각한 부분은 미리 get으로 필요한부분을 호출하도록 생각해보았는데 로직상 뜬금없기도 하고 LAZY로딩에 의미가 없어지는것 같기도 한데 아니면 혹은 더 좋은 방법이 있을까요?)