묻고 답해요
138만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
양방향 연관관계에서 연관관계 편의 메서드 위치에 대해 질문드립니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요. 좋은 강의 덕분에 양질의 지식을 비교적 수월하게 습득하고 있습니다.양방향 연관관계에서 편의 메서드는 어디에 위치하는게 좋은지 여쭙고자 합니다.(비슷한 질문들을 봤지만 이러한 경우에 어떤게 가장 좋은 선택일지 궁금하여 질문드립니다.)비슷한 질문1 : https://www.inflearn.com/questions/16308비슷한 질문2 : https://www.inflearn.com/questions/99330 현재상태위와 같이 일대다(1:N) 관계가 있고 Team 을 애그리거트 루트로 잡았습니다.도메인 룰은 다음과 같습니다.Team 은 반드시 이름이 있어야한다.Player는 반드시 이름과 나이가 있어야한다.Player는 반드시 Team에 소속되어야하며, 하나의 Team 에만 소속될 수 있다.player 의 Team 은 변경될 수 없다.엔티티 코드 입니다. (연관관계 편의 메서드를 애그리거트 루트쪽에 두었습니다.)(두 엔티티는 동일한 패키지에 있습니다. package com.example.jpa.module.team.domain;)@Entity public class Team { @Id @GeneratedValue private Long teamNo; private String name; @OneToMany(mappedBy = "team", cascade = CascadeType.ALL) private List<Player> players = new ArrayList<>(); //생성자 public Team(String name) { this.name = name; } //연관관계 편의 메서드 public void addPlayer(Player player) { player.setTeam(this); this.players.add(player); } }@Entity public class Player { @Id @GeneratedValue private Long playerNo; private String name; private Integer age; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "team_no") private Team team; //생성자 public Player(String name, int age) { this.name = name; this.age = age; } void setTeam(Team team) { this.team = team; } }service 계층 코드입니다.Team team = new Team("team1"); Player player = new Player("kim", 24); team.addPlayer(player); teamRepository.save(team);Team 이 Player 를 완전히 소유하는 관계이기 때문에 애그리거트 루트를 Team 으로 잡았고 연관관계 메서드 또한 Team 에 있는게 자연스러워 보입니다.(예시가 Team-Player라 결합도가 좀 떨어지는것 처럼 느껴지는데 주문-주문항목 이나 게시글-첨부파일 같은 관계로 봐주시면 감사하겠습니다.)문제점연관관계 편의 메서드 addPlayer(..)가 호출되기 전까지 Player의 도메인 룰이 깨진 상태가 됩니다.도메인 룰 3번 "Player 는 반드시 Team에 소속되어야 한다" 를 위반하게 됩니다.Player의 setTeam(..) 메서드를 클래스 외부에 공개해야 합니다.같은 패키지라 public 으로 공개하진 않았지만 해당 메서드로 인해 도메인 룰 4번 "player 의 Team 은 변경될 수 없다." 를 위반할 여지가 생겼습니다.setTeam(..) 메서드에 this.team != null 인 경우 예외를 발생시켜 도메인 룰을 지킬 수 있지만 좋은 방법인지 잘 모르겠습니다..시도한 방법Player의 생성자에 Team을 받도록 합니다.public Player(Team team, String name, int age) { this.team = team; this.name = name; this.age = age; }근데 이렇게 하니 그냥 연관관계 편의 메서드를 Player에 두는게 나은것 같아 생성될때 연관관계를 맺도록 정적 팩토리 메서드를 작성했습니다.public static Player createAndLink(Team team, String name, int age) { Player player = new Player(team, name, age); //생성자 private 으로 변경 team.getPlayers().add(player); //반대편 연관관계 설정 return player; }일단 도메인 룰은 모두 만족하는 듯 보이나 service 계층 코드가 뭔가 부자연스럽습니다.Team team = new Team("team1"); Player player = Player.createAndLink(team, "kim", 24); teamRepository.save(team);위 코드를 보면 player를 생성하고 사용하지 않는것 처럼 보여 불필요한 코드로 인식됩니다.(인텔리제이에서도 player가 미사용 중이라고 나옵니다.)혹시 위와 같은 상황에서 어떻게 해결하는게 가장 좋은 방법일까요?(긴 글 읽어주셔서 감사합니다.)
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
test오류
테스트 진행 중 오류가 납니다.구글링해두 해결을 못하겠네요 ㅠㅠ어쩌다가 테스트 진행이 됐었는데 시퀀스를 계속 삭제해줘야 됐었습니다.H2 1.4.200 버전맞고 다른 소스들 교재랑 같습니다.스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의 듣고 기존에 쓰던 H2에서 database만 추가해서 사용중인데 이게 문제가 될까요? java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@597a7afa testClass = jpabook.jpashop.MemberRepositoryTest, locations = [], classes = [jpabook.jpashop.JpashopApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceLocations = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@9da1, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@49d904ec, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@3c419631, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@3e2e18f2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@63355449, org.springframework.boot.test.context.SpringBootTestAnnotation@8c81e9cd], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:141) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:127) at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:192) at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:249) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:290) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:292) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97) at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) 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$3.evaluate(ParentRunner.java:306) at org.junit.runners.ParentRunner.run(ParentRunner.java:413) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) 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$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not instantiate id generator [entity-name=jpabook.jpashop.Member] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1751) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1130) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:905) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137) at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:59) at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:47) at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1386) at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:543) at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137) at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108) at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:183) at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117) ... 27 moreCaused by: jakarta.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not instantiate id generator [entity-name=jpabook.jpashop.Member] at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:421) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:352) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1797) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1747) ... 48 moreCaused by: org.hibernate.MappingException: Could not instantiate id generator [entity-name=jpabook.jpashop.Member] at org.hibernate.id.factory.internal.StandardIdentifierGeneratorFactory.createIdentifierGenerator(StandardIdentifierGeneratorFactory.java:222) at org.hibernate.mapping.SimpleValue.createIdentifierGenerator(SimpleValue.java:515) at org.hibernate.mapping.SimpleValue.createIdentifierGenerator(SimpleValue.java:372) at org.hibernate.internal.SessionFactoryImpl.lambda$new$1(SessionFactoryImpl.java:291) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1779) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:290) at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:415) at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1425) at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66) at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:376) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ... 52 moreCaused by: org.hibernate.HibernateException: Could not fetch the SequenceInformation from the database at org.hibernate.engine.jdbc.env.internal.ExtractedDatabaseMetaDataImpl.sequenceInformationList(ExtractedDatabaseMetaDataImpl.java:302) at org.hibernate.engine.jdbc.env.internal.ExtractedDatabaseMetaDataImpl.getSequenceInformationList(ExtractedDatabaseMetaDataImpl.java:151) at org.hibernate.id.enhanced.SequenceStyleGenerator.getSequenceIncrementValue(SequenceStyleGenerator.java:561) at org.hibernate.id.enhanced.SequenceStyleGenerator.configure(SequenceStyleGenerator.java:210) at org.hibernate.id.factory.internal.StandardIdentifierGeneratorFactory.createIdentifierGenerator(StandardIdentifierGeneratorFactory.java:217) ... 70 moreCaused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "start_value" not found [42122-214] at org.h2.message.DbException.getJdbcSQLException(DbException.java:502) at org.h2.message.DbException.getJdbcSQLException(DbException.java:477) at org.h2.message.DbException.get(DbException.java:223) at org.h2.message.DbException.get(DbException.java:199) at org.h2.jdbc.JdbcResultSet.getColumnIndex(JdbcResultSet.java:3492) at org.h2.jdbc.JdbcResultSet.getLong(JdbcResultSet.java:745) at com.zaxxer.hikari.pool.HikariProxyResultSet.getLong(HikariProxyResultSet.java) at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.resultSetStartValueSize(SequenceInformationExtractorLegacyImpl.java:110) at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.lambda$extractMetadata$0(SequenceInformationExtractorLegacyImpl.java:54) at org.hibernate.tool.schema.extract.spi.ExtractionContext.getQueryResults(ExtractionContext.java:50) at org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl.extractMetadata(SequenceInformationExtractorLegacyImpl.java:39) at org.hibernate.engine.jdbc.env.internal.ExtractedDatabaseMetaDataImpl.sequenceInformationList(ExtractedDatabaseMetaDataImpl.java:286) ... 74 more
-
해결됨실전! 스프링 데이터 JPA
양방향 연관관계에서 관계를 바꿀 때
[질문 내용]안녕하세요. 예전 부터 궁금했던 내용인데, 혹시 나중에 나오지 않을까 해서 미루다가 결국 질문합니다..! public void changeTeam(Team team){ this.team = team; team.getMembers().add(this); }예전 강의에서는 양방향 연관 관계에서 주인이 관계를 변경할 때 위처럼 Member Entity는 자신의 필드에 새로운 Team을 세팅하고 Team은 Member를 list에 추가하는 식으로만 마무리했던 것으로 기억합니다. 지나가는 말로 영한님께서 기존 Member와 연관 관계에 있던 Team list에서 Member를 remove하는 작업도 해야 하는데, 연습하는 거니까 빼셨다고 하셨던 것 같습니다. 이 부분이 조금 궁금했습니다.관계가 바뀌기 이전의 기존 Member의 Team list에서 Member를 지워 주는 부분을 어떤식으로 작성해야 할 지 조금 감이 안 잡힙니다..ㅠㅠ고려할 사항이 너무나도 많다고 해야 할까요.. public void changeTeam(Team team){ this.team.getMembers().remove(this); this.team = team; team.getMembers().add(this); }위처럼 단순히 remove()를 사용하기에는 몇 가지 고려할 사항들이 있었습니다.첫 번째 문제는 remove()의 경우 add와 달리 list의 Member들을 필요로 하는 로직이 들어 있기 때문에 DB로부터 Team의 Member list 정보를 불러온 다음에 동작한다는 점입니다.특정 로직은 Team의 Members를 사용할 일이 없어 굳이 DB와 Entity그래프를 일치시킬 필요가 없는데, remove()로직이 들어가면서 DB를 조회하는 일이 생긴다는 점입니다. 이로 인한 성능상 문제는 정말 미세하겠지만, 뭔가 조금 걸리는 느낌입니다.. 두 번째는 remove()를 할 때에 eqauls()를 사용한다는 점입니다.단순히 equals()를 오버라이딩하여 구현하면 될 줄 알았지만, 이 부분도 고려할 부분이 생각 보다 많았습니다.크게 세 가지로 나뉘는 것 같았습니다.pk를 이용한 equals()오버라이딩pk와 연관관계 필드를 제외한 필드로 eqauls()를 오버라이딩Business-Id를 이용한 eqauls()오버라이딩이렇게 세 가지 사항 정도가 고려되는 것 같았습니다.각각의 장단점이 있어 보였는데, 3번이 제일 괜찮은 방식으로 보였습니다.1번은 pk가 GenerateValue방식일 경우 Entity가 persist되기 이전에는 pk를 초기화하지 못 해, set과 같은 Collection을 사용할 때 제한이 생긴다는 점이나 NPE발생 가능성 내재, pk값이 null인 객체가 같은 객체로 인식이 되는 위험, 비영속 상태 객체와 영속 상태 객체의 eqauls연산 시 일치 불가 등이 있는 것 같았습니다. 사실 위의 문제점들이 발생할 만한 로직을 실제 작성하게 될 일이 많지는 않을 것 같지만 뭔가 내재된 위험이 많아 보여 패스했습니다.2번은 pk와 연관 관계 필드를 제외한 모든 필드들이 합쳐서 Unique한 값을 갖지 못할 경우 중복이 발생하는 문제점이 있어 보였습니다.3번이 제일 적절해 보였지만 Business-Id로 사용할 만한 데이터가 없을 경우 문제가 있을 것 같았습니다.특정 글에서는 UUID와 같이 Business-Id를 일부로 두기도 한다는 것 같은데 괜찮은 방식인 지는 모르겠습니다. 내용이 길어졌는데 결론은 양방향 연관 관계에서 관계를 바꿔 줄 때 Entity 그래프를 일치시키기 위해서 어떤 형태로 로직을 작성하는 지 궁금하다는 것입니다.이렇게 보니 제가 너무 이상한 방식으로 접근한 게 아닌가 생각이 듭니다ㅠㅠ 현업에서는 어떤 식으로 구현하는 지 궁금한데 혼자 공부하다 보니 마땅히 예시를 볼만한 곳이 없어 질문드립니다. 긴 글 읽어 주셔서 감사합니다..! (_ _)
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
6분 45초쯤 양방향 연관관계에 대해서 간단한 질문이 있습니다.
6분 45초쯤에 말씀을 하시는게 지금 이 강의는 예제로 보여주기 위해 Member와 Order가 일대다, 다대일로 양방향 연관관계를 이루고 있지만실무에서는 이렇게 양방향으로 짜기보단 Order가 Member를 참조하게 되는 다대일만 써주는 것이 좋다.이 말이 혹시 맞을까요...?그리고 추가로 Order와 OrderItem의 관계에서는 양방향 연관관계를 안쓰려고 하면 OrderItem이 Order를 참조하는 것으로만 설계를 하면 되는건가요...?
-
해결됨실전! Querydsl
count 쿼리 최적화 질문 드립니다.
안녕하세요! 영한님^^개발자들을 위해여 양질의 강의를 제공해주셔서 정말로 감사의 말씀을 드립니다.🙏 질문드리겠습니다. 먼저 제가 이해한 내용을 말씀드리겠습니다.PageableExecutionUtils를 사용하면 count 쿼리 최적화하 가능 하다고 말씀하셨습니다.그 이유는 람다를 사용하여 게으른 호출로 인하여 실제 사용되기 전까지는 함수가 실행되지 않는다고 이해했습니다. 다음 2가지 경우에 count 쿼리가 실행되지 않다고 말씀하셨습니다.페이지 시작이면서 컨텐츠 사이즈가 페이지 사이즈 보다 작을때페이지 시작(0)이면서 컨텐츠 사이즈(3)가 페이지 사이즈(10)보다 작다면 컨텐츠 사이즈(3)가 카운트 갯수 마지막 페이지 일때(offset + 컨텐츠 사이즈 = 카운트)예를 들어 전체 데이터는 103개이고, 페이지 사이즈는 10이라고 한다면마지막 페이지 일때는 offset(100), 컨텐츠 사이즈(3)이라서 카운트는 103으로 이해 하고 있는데 맞는 내용 인가요? 감사합니다.^^
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
JWT 이용한 로그인 구현
안녕하세요.백엔드는 스프링, 프론트엔드는 리액트를 이용해서 리프레쉬 토큰과 엑세스 토큰으로 로그인을 구현할 때 한번 로그인을 하면 같은 브라우저 안에 있는 탭끼리는 로그인 상태를 유지시키고 싶은데 리프레쉬 토큰과 엑세스 토큰을 어디에 저장하고 어떻게 관리해야 되는지 궁급합니다.
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
생성 메서드와 연관관계 주인 질문드립니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예[질문 내용]public static OrderItem createOrderItem(Item item,int orderPrice, int count)강의 중 생성메서드를 구현하는 부분 중OrderItem 생성메서드를 생성할때 파라미터로 Order order를 추가하지 않은 것에 대한 이유가 궁금하여 질문드립니다.OrderItem 엔티티에서 order필드가 연관관계의 주인이기에 null이 되면 안된다 생각하였고 그렇기에생성메서드 파라미터에도 Order order를 꼭 넣어줘야 하는게 아닌지 궁금점이 들어 질문드립니다!!감사드립니다!
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
@BatchSize의 조회 대상 우선순위(?)
[질문 내용]안녕하세요 강의 너무 잘 듣고 있습니다.@BatchSize에 관해서 의문점이 생겨서 질문을 드리게 되었습니다. @BatchSize를 사용하면 특정 Entity에서 조회 쿼리가 필요한 필드를 초기화 할 때, 1차 캐시로부터 같은 종류의 Entity id값을 @BatchSize에 지정한 size값만큼 가져와 IN에 넣어서 필요한 데이터를 함께 조회하고 초기화하는 것으로 이해했습니다.근데, 이 때 단순히 1차 캐시에서 랜덤으로 id값을 가져와서 IN에 넣으면 원하지 않는 Entity에 초기화가 잘못 이뤄질 수 있지 않을까 하는 의문이 있었지만, 당연하게도 이런 부분에 대해서는 알아서 최적화를 해 둔 것 같았습니다. 예를 들면 JPQL의 결과로 조회된 Entity컬렉션 내부에서 하나를 집어 Entity 필드를 지연 로딩 초기화할 경우 같은 컬렉션 내부의 Entity들이 우선순위를 갖고 함께 초기화되는 것 같았습니다.하지만 이것이 정확히 어떤 원리로 동작하는 지는 알 수가 없었습니다..ㅠㅠ JPQL로 조회한 컬렉션에 대해서 따로 영속성 컨텍스트가 참조하고 있다거나 하는 식으로 동작하는 것일까요? 이런 원리를 모르다 보니 @BatchSize가 IN에 넣을 Entity를 결정하는 우선순위를 알 수가 없었습니다.@BatchSize의 size값이 JPQL로 조회한 컬렉션의 size보다 클 때에는 1차 캐시에서 부족한 만큼의 Entity id를 더 끌어와서 IN에 추가하는데, 이 때 함께 초기화될 Entity가 어떤 Entity일 지 예측이 안 됩니다. 이런 것들도 우선순위가 따로 존재하나요? 크게 중요한 내용은 아닌 것 같은데, 그냥 같은 컬렉션에 있는 Entity들이 IN의 우선순위가 된다고 이해하고 사용하는 정도면 문제가 없을 지 궁금합니다..!
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
포폴 데이터모델링, jpa설계하다가 질문 !!
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요?? 김영한님 JPA강의 덕에 포폴 순항하고 있습니다. 항상 좋은 강의 감사한 마음을 가지고 있습니다. 파이팅하세요 !!궁금한점을.... 간단하게 설명하려고 노력하겠습니다 !!예를들어서 블로그 포스팅 domain을 아래와 같이 만들었습니다...id: ~~~~content: ~~~~tags: ~~~ (일대다 관계)comments: ~~~(일대다 관계)그런데 !!! 여기서 궁금한점 !!제 생각으로는...아 그냥 편하게 포스팅한번에 끌고와서(tags, comments) 응답해주고 싶은뎅...그런데 영한님께서는 이 강의에서 일대다 관계를 두번이상하면 안된다고 하셔서...ㄷㄷ;;;;그래서, 오랜 고민끝에 포스팅 (id,content,tags)를 응답해주고 comments는 다대일 방법으로 응답을 해줬거든요??.... (이게 옳은방법일까...ㄷㄷ;;)그러니까 요청을 두번 보내는거에요..포스팅 한번... 포스팅에 연관관계있는 comments 한번..저의 이러한 판단과 설계과 괜찮은 걸까요??질문드리고 싶습니다 !! (잘 이해하셨을라나...ㄷㄷ;ㅠㅠ)
-
미해결생산성을 향상시키는 스프링부트 기반의 API 템플릿 프로젝트 구현
API response에 대한 질문
안녕하세요!먼저 좋은강의 만들어주셔서 감사합니다.다름이 아니라, 강의보면서 궁금한점이 생겨 문의드립니다.지금 에러(exception)가 발생하면 공통적으로 ErrorResponse 객체를 반환하게 만들어서 에러처리를 일관성있게 할 수있게 만드신것 같습니다.그런데 혹시 성공적인 응답일 때는 이런 객체를 만들지 않아도 되나요? 예를 들면 SuccessResponse 등을 만들어서 응답으로 주는 데이터를 다시 한번 감싸서 준다던가 하는게 더 좋을지, 아니면 그냥 응답dto 객체만 넘겨주면 되는지 궁금합니다!
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
jpql flush 자동 호출
jpql flush 자동 호출되는 것이 커밋까지 된다는 말씀이실까요?jpql 로 db 에서 데이터를 조회하려면 db 에 반영이 되어야할 것 같아서입니다.
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
V4 에서 DTO로 조회시 즉시 로딩이 되는 건가요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]V4 에서는 fetch join을 사용하지 않으셨는데 조회 쿼리는 한번만 나가는 것을 확인했습니다. dto로 조회를 하면 Lazy로딩으로 세팅해도 즉시 로딩으로 나간다고 이해하면 될까요?
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
프록시 객체에 대해 질문이 잇습니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요. 프록시 강의를 보고 궁금한게 생겨 질문드립니다. 먼저 member객체를 생성하고 member.setUserName("hello");로 이름을 설정하고 persist(member); 하시고 바로 flush를 하셨습니다. 이후에 em.getReference(Member.class, member.getId());를 하시고 getId와 getUserName을 하실때 getId는 이미 getReference를 할때 getId(이미 있는 값이라 하셨습니다)를 사용해서 db에서 조회할 일이 없었다 라고 하셨고 getUserName은 db에서 조회해야한다 라고 하셨었는데 처음에 member객체에서 setUserName으로 값을 넣어주었고 id도 generatedValue로 값이 자동으로 설정되어서 2개의 값이 flush하기 전에 세팅이 되었는데 왜 id는 조회할때 이미 있는값이라 select문이 안나가고 userName은 값이 없어 select문이 나간건지 궁금합니다(설명을 잘 못해서 죄송합니다 ㅜ... 이해가 잘 안간탓에... 답변 해주시면 감사하겠습니다)
-
미해결생산성을 향상시키는 스프링부트 기반의 API 템플릿 프로젝트 구현
JWT 기반 인증 관련 질문
안녕하세요. 좋은 강의 잘 듣고 있습니다.다름이 아니라, JWT 기반 인증으로 회원을 관리할 때 소셜로그인 외에 서비스에 자체적인 회원가입 기능이 있는 경우에는 어떤식으로 관리해야 할까요?자체 회원가입 / 로그인 기능 등을 스프링 시큐리티를 사용해서 JWT 토큰을 발급할 수 있도록 하려고 했는데, 그 경우엔 시큐리티를 이용하려면 기존에 사용하던 인터셉터 대신 필터를 사용하여 시큐리티에 등록해야 될까요?아니면 시큐리티를 사용하지 않고 그냥 로그인할 때 소셜로그인처럼 AccessToken 과 RefreshToken을 자체적으로 만들어 발급해주는 식으로 구현해도될까요?
-
미해결실전! Querydsl
BooleanExpression 모든 조건이 null 일 때
이 경우 where절이 빠짐에 따라 테이블의 모든 데이터가 나오는 건 이해했습니다. 테이블 데이터가 많을 경우 select를 많이 하느라 장애가 난다까진 알겠는데, 그렇다면 이걸 해결할 수 있는 게 페이징뿐인가요? 어떠한 사정이나 목적 때문에 페이징 적용이 되지 않은 쿼리의 경우, 이걸 방지하기 위한 방법이 있는지 궁금합니다.
-
미해결스프링 시큐리티
SecurityResourceService 에서 JPA proxy 관련 질문이 있습니다!
안녕하세요 강사님! 좋은 퀄리티의 Security 강의 제공해주셔서 감사드립니다.[실전프로젝트 - 인가 프로세스 DB 연동 웹 계층 구현]5) 웹 기반 인가처리 DB 연동 - FilterInvocationSecurityMetadataSource (2)수강하면서 생겼던 질문이 있습니다.// val resourcesList = resourcesRepository.findAllResources() val resourcesList = resourcesRepository.findAll()강사님께서 미리 만들어두셨던 findAllResources 메소드를 통한 JPQL로 fetch하지 않고 Spring DataJPA 기본 findAll 메소드로 resources 리스트 가져와서 Role의 roleName을 LinkedHashMap에 넣었습니다.(해당 서비스 클래스의 getResourceList 메소드에는 @Transactional 걸어둔 상태입니다.)그렇게 하니까 다음과 같은 에러가 발생했었습니다.failed to lazily initialize a collection of role: io.beaniejoy.coresecurity.domain.entity.Resources.roleSet, could not initialize proxy - no SessionResources 엔티티에 @ManyToMany로 roleSet에 fetch 모드를 LAZY로 걸어둔 상태여서 저는 lazy한 방식으로 proxy를 통해 role.getRoleName() 할 때 role_resources, role 두 테이블로 조회쿼리 날라가면서 잘 가져올 것이라 생각했었는데요. 왜 proxy를 initialize 하지 못했는지, resources를 findAll할 때 결국 fetch join으로 가져올 수 밖에 없는 것인지 궁금했습니다.(제가 JPA를 잘 알지 못하여 죄송합니다.)
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
비대칭키 jwt 인증 문제
http://localhost:8888/ecommerce/default 에서는 {name: "ecommerce",profiles: ["default"],label: null,version: "f45bf692a6cb54252ea12041f0aa92a71964a5f7",state: null,propertySources: [{name: "file:///C:\\Users\\ydj90\\Downloads\\git/file:C:\Users\ydj90\Downloads\git\ecommerce.yml",source: {token.expiration_time: 864000000,gateway.ip: "172.30.1.33",token.secret: "userToken_token"}}]}http://localhost:8888/user-service/default 에서는{name: "user-service",profiles: ["default"],label: null,version: "f45bf692a6cb54252ea12041f0aa92a71964a5f7",state: null,propertySources: [{name: "file:///C:\\Users\\ydj90\\Downloads\\git/file:C:\Users\ydj90\Downloads\git\user-service.yml",source: {spring.datasource.url: "jdbc:h2:mem:testdb",spring.datasource.driver-class-name: "org.h2.Driver",spring.datasource.generate-unique-name: false,token.expiration_time: 864000000,gateway.ip: "172.30.1.33",order_service.url: "http://ORDER-SERVICE/order-service/%s/orders",spring.datasource.username: "sa",token.secret: "userToken_token"}}]} 이와 같이 token.secret이 같은데 왜 subject가 null값이 되는지 이유를 알 수 가 없습니다. login하고 나온 header값을 가지고 bearer에 넣어 인증하는 방식이 아닙니까?이유를 잘 모르겠습니다. JWT token is not valid이게 왜 뜨는지subject = Jwts.parser().setSigningKey(env.getProperty("token.secret")) .parseClaimsJws(jwt).getBody() .getSubject(); 여기서 왜 null값으로 값을 반환하는지 이해를 할 수가 없습니다.
-
미해결실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화
컬렉션타입이라는게...정확히 뭔가요?
컬렉션타입이 었었다 라고 하시는데혹시 컬렉션타입이라는게 @Embeded 와 관련되어 Address 이런 클래스를 일컫는말인가요?
-
미해결실전! Querydsl
q class 생성 이유
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]Querydsl 사용 시 Q class 생성 이유가 궁금합니다.
-
해결됨실전! Querydsl
Quarydsl 로 no-offset 페이지네이션이 구현가능할까요?
[질문 내용]여기에 질문 내용을 남겨주세요.김영한님 로드맵중 실전로드맵 패키지 듣고있는데,restapi설계중에 무한스크롤을 구현해야하는 시점에강의 내용에 Quarydsl로 페이지네이션 강의가 나와서 여쭤봅니다no-offset 방식으로 페이지네이션이 구현 가능할까요 ? 가능하다면 어떤식으로 구현해야할까요..