안녕하세요. 앞서 전파기본 강의와 전파예제 강의를 듣고나서 이해가 되지않는 부분이 몇가지 있어서 질문드립니다. 1. 강의 자료중에, 트랜잭션매니저에 커밋하는것이 논리적인 커밋이라면, 실제커넥션에 커밋하는것을 물리 커밋이라고 할수있다 = 내부트랜잭션인 txManager.commit(inner)을 하는것이 논리적인 커밋이고, 외부트랜잭션인 txManager.commit(outer)을 하는것이 물리커밋이다. = 트랜잭션 매니저를 통해 txManager.commit(inner)를 하는것이 논리적인 커밋이고, 트랜잭션 매니저를 통해 txManager.commit(outer)를 하는것이 물리커밋이다. 이렇게 생각하는게 맞을까요?? 2. 1번 질문에 더해서, 트랜잭션 매니저를 통해서 txManager.commit()을 하는것이 논리적인 커밋이라면, 물리적인 커밋은 코드상 어떤것인가요? 외부트랜잭션도 txManager.commit()을 통해 커밋하는거같은데, 이렇게 외부트랜잭션을 커밋하는것이 논리적인 커밋임과 동시에 물리커밋인것인가요?? 3. 외부트랜잭션도 논리트랜잭션이고 내부트랜잭션도 논리트랜잭션인가요? 그래서 이 두가지를 묶어서 물리트랜잭션이라고 하는것인가요??
[질문 내용] 스프링 부트와 JPA 활용 1편에서 제가 작성한 코드에서는 POST: http://localhost:8080/api/v1/members 해당 API가 잘 작동하는데 스프링 부트와 JPA 활용 2편에서 제공하신 강의 소스에서는 작동이 안되어서 문의드립니다. 해당 사진처럼 오류가 발생(상태코드 500) 아래 링크에 있는 내용대로 패키지 이름 변경은 다 했습니다. (javax -> jakarta) https://docs.google.com/document/d/1j0jcJ9EoXMGzwAA2H0b9TOvRtpwlxI5Dtn3sRtuXQas/edit?tab=t.0#heading=h.vfy9wirpglmx
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문 전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예 [질문 내용] 여기에 질문 내용을 남겨주세요. 아래의 메서드는 결국 if(closed) 를 검증하기 위한 코드인데 synchronized가 아닌 volatile 키워드로 가시성만 보장해도 동시성 처리를 막을 수 있을 것 같다는 생각에 질문 드립니다! 아직까지 해당 부분이 미흡해서 다시 공부해보겠습니다! public synchronized void close() { if (closed) { return; } closeAll(socket, input, output); // shutdown closed = true; log("연결 종료: " + socket); }
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 안녕하세요. 강사님의 강의를 들으며 코드를 작성하던 도중 해결되지 않는 의문이 생겨 질문게시판에 글을 남깁니다. 강의를 보며 샘플데이터 추가를 위한 코드를 작성하고 나서 QuerydslApplication을 실행하면 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'initMember': Invocation of init method failed 이라는 오류코드가 뜨면서 QuerydslApplication실행이 종료 됩니다. 그런데 김영한 강사님이 올려주신 자료의 코드를 넣어서 실행해 보면 QuerydslApplication 실행이 잘 됩니다. 분명 똑같이 만들었는데 왜 이런 차이가 나는걸까요? 코드도 다른점이 없어보이는데 이러한 차이가 생기는 이유가 궁금합니다. 아래는 제가 작성한 코드(수정 전 샘플데이터)와 김영한 강사님의 코드(수정후 샘플데이터)입니다. package study.querydsl; import jakarta.annotation.PostConstruct; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import study.querydsl.entity.Member; import study.querydsl.entity.Team; //샘플데이터 추가 /*수정 전 샘플데이터*/ /*@Profile("local") @Component @RequiredArgsConstructor public class InitMember { private final InitMemberService initMemberService; @PostConstruct public void init() { initMemberService.init(); } @Component static class InitMemberService { @PersistenceContext private EntityManager em; @Transactional private void init() { Team teamA = new Team("teamA"); Team teamB = new Team("teamB"); em.persist(teamA); em.persist(teamB); for (int i = 0; i < 100; i++) { Team selectedTeam = i % 2 == 0 ? teamA :teamB; em.persist(new Member("member" + i, i, selectedTeam)); } } } }*/ /*수정후 샘플데이터*/ @Profile("local") @Component @RequiredArgsConstructor public class InitMember { private final InitMemberService initMemberService; @PostConstruct public void init() { initMemberService.init(); } @Component static class InitMemberService { @PersistenceContext EntityManager em; @Transactional public void init() { Team teamA = new Team("teamA"); Team teamB = new Team("teamB"); em.persist(teamA); em.persist(teamB); for (int i = 0; i < 100; i++) { Team selectedTeam = i % 2 == 0 ? teamA : teamB; em.persist(new Member("member" + i, i, selectedTeam)); } } } }
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 안녕하세요 강사님. 강의 수강 중에 질문 드려봅니다. 섹션9. 프록시 1편 11분경에, 코드를 그대로 따라 치고 실행해보았는데, 실제로 강의와 다르게 동작하는 거 같습니다. try { Member member = new Member(); member.setUsername("hello"); em.persist(member); em.flush(); em.clear(); Member findMember = em.getReference(Member.class, member.getId()); System.out.println("findMember.id = " + findMember.getId()); System.out.println("findMember.username = " + findMember.getUsername()); tx.commit(); } catch (Exception e) { tx.rollback(); } finally { em.close(); } 위와 같이 코드를 실행했는데요, Hibernate: select next value for Member_SEQ Hibernate: /* insert for hellojpa.Member */insert into Member (USERNAME, MEMBER_ID) values (?, ?) Hibernate: select m1_0.MEMBER_ID, t1_0.TEAM_ID, t1_0.name, m1_0.USERNAME from Member m1_0 left join Team t1_0 on t1_0.TEAM_ID=m1_0.TEAM_ID where m1_0.MEMBER_ID=? findMember.id = 1 findMember.username = hello 콘솔에서는 이렇게 나옵니다. findMember.id는 쿼리 실행 필요 없이 바로 출력 가능해야 할 거 같은데 쿼리가 먼저 실행되는 이유가 뭘까요? (username을 꺼내쓰는 부분을 제거하고 실행해봐도 쿼리가 실행되고 id를 출력합니다.)
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 강의에서 order 테이블을 조회하면 id값이 4, 11로 나오는데 저는 1, 2로 나옵니다. 아무리 생각해봐도 4, 11로 나올 이유가 없어보이는데 왜 4,11로 나오는지 궁금합니다
안녕하세요 비슷한 이유로 queryDSL 에서 불편함을 가지고 있어 jOOQ 에 관심이 생겼습니다. 마침 이렇게 좋은 강의 만들어주셔서 정말 감사합니다. 다름이 아니라 kotlin 을 주로 사용해서 kotlin 으로 jOOQ 사용시 컴파일 단계에서 힙메모리 부족 현상이 생기는데 혹시 kotlin 으로 힙메모리 부족 현상을 겪으신 적 있으신가요 만약 있으시면 해결하신 지혜를 얻고 싶어 글 남깁니다 gradle 설정은 아래와 같이 했습니다 해결과정 동안 힙메모리 설정 추가하여 늘려봐도 메모리 부족 현상이 발생하네요 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile val jooqVersion: String by extra("3.19.5") plugins { kotlin("jvm") version "1.9.25" kotlin("plugin.spring") version "1.9.25" id("org.springframework.boot") version "3.4.0" id("io.spring.dependency-management") version "1.1.6" id("nu.studer.jooq") version "9.0" } group = "com.example" version = "0.0.1-SNAPSHOT" java { toolchain { languageVersion = JavaLanguageVersion.of(21) } } repositories { mavenCentral() } dependencies { implementation("org.springframework.boot:spring-boot-starter-jooq"){ exclude(group = "org.jooq", module = "jooq") } implementation("org.jooq:jooq:$jooqVersion") // jOOQ implementation(project(":jOOQ-custom")) jooqGenerator (project(":jOOQ-custom")) jooqGenerator("org.jooq:jooq:$jooqVersion") jooqGenerator("org.jooq:jooq-meta:$jooqVersion") implementation("org.jetbrains.kotlin:kotlin-reflect") runtimeOnly("com.mysql:mysql-connector-j") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") testRuntimeOnly("org.junit.platform:junit-platform-launcher") } kotlin { compilerOptions { freeCompilerArgs.addAll("-Xjsr305=strict") } } tasks.withType<Test> { useJUnitPlatform() } val dbUser: String = System.getProperty("db-user") ?: "root" val dbPassword: String = System.getProperty("db-password") ?: "passwd" jooq { version.set(jooqVersion) configurations { create("sakilaDB") { generateSchemaSourceOnCompilation.set(true) jooqConfiguration.apply { logging = org.jooq.meta.jaxb.Logging.WARN jdbc.apply { driver = "com.mysql.cj.jdbc.Driver" url = System.getenv("DB_URL") ?: "jdbc:mysql://localhost:3306/sakila" user = dbUser password = dbPassword } generator.apply { name = "org.jooq.codegen.KotlinGenerator" database.apply { name = "org.jooq.meta.mysql.MySQLDatabase" excludes = "sys" } generate.apply { isDaos = true isRecords = true isFluentSetters = true isJavaTimeTypes = true isDeprecated = false } target.apply { directory = "src/generated" } strategy.name = "com.example.jooq.custom.generator.JPrefixGeneratorStrategy" } } } } } sourceSets { main { java { srcDirs("src/main/kotlin", "src/generated") } } }
안녕하세요. 그런데 섹션3 의 'Querydsl 검색처리' 영상을 다 보고 TDD 테스트를 돌리는데 계속 아래와 같은 에러가 납니다.. 몇일동안 찾아봤는데도 아예 해결이 되지 않아서 여기에 질문드리게 됐네요.. ㅠㅠ 혹시 몰라 콘솔탭에 있는거 전부 다 복사해 왔습니다. 강의를 파트별로 정리하면서 공부하고 있어서 앞에 Ex01 이런식으로 이름이 붙어 있습니다. 왜 안되는지 도저히 모르겠어요.. (게시글이 10000자 이상 안써진다고 해서 댓글에 다음 메세지들 쓰겠습니다.) (혹시 몰라서 대댓글로 코드들도 남깁니다.) . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.3.6) 2024-12-02T05:13:22.977+09:00 INFO 7780 --- [ restartedMain] c.zerock.apiserver.ApiserverApplication : Starting ApiserverApplication using Java 17.0.13 with PID 7780 (C:\Users\hykim\Desktop\apiserver\build\classes\java\main started by hykim in C:\Users\hykim\Desktop\apiserver) 2024-12-02T05:13:22.993+09:00 INFO 7780 --- [ restartedMain] c.zerock.apiserver.ApiserverApplication : No active profile set, falling back to 1 default profile: "default" 2024-12-02T05:13:23.010+09:00 INFO 7780 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable 2024-12-02T05:13:23.010+09:00 INFO 7780 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG' 2024-12-02T05:13:23.322+09:00 INFO 7780 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2024-12-02T05:13:23.353+09:00 INFO 7780 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 28 ms. Found 1 JPA repository interface. 2024-12-02T05:13:23.632+09:00 INFO 7780 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) 2024-12-02T05:13:23.638+09:00 INFO 7780 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2024-12-02T05:13:23.638+09:00 INFO 7780 --- [ restartedMain] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.33] 2024-12-02T05:13:23.665+09:00 INFO 7780 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2024-12-02T05:13:23.665+09:00 INFO 7780 --- [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 655 ms 2024-12-02T05:13:23.733+09:00 INFO 7780 --- [ restartedMain] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] 2024-12-02T05:13:23.761+09:00 INFO 7780 --- [ restartedMain] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.5.3.Final 2024-12-02T05:13:23.777+09:00 INFO 7780 --- [ restartedMain] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled 2024-12-02T05:13:23.936+09:00 INFO 7780 --- [ restartedMain] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer 2024-12-02T05:13:23.951+09:00 INFO 7780 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2024-12-02T05:13:23.989+09:00 INFO 7780 --- [ restartedMain] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection org.mariadb.jdbc.Connection@6303bda2 2024-12-02T05:13:23.990+09:00 INFO 7780 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2024-12-02T05:13:24.411+09:00 INFO 7780 --- [ restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) 2024-12-02T05:13:24.438+09:00 INFO 7780 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2024-12-02T05:13:24.535+09:00 WARN 7780 --- [ restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ex04_10_TodoServiceImpl' defined in file [C:\Users\hykim\Desktop\apiserver\build\classes\java\main\com\zerock\apiserver\service\Ex04_10_TodoServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'ex04_13_TodoRepository' defined in com.zerock.apiserver.repository.Ex04_13_TodoRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Could not create query for public abstract org.springframework.data.domain.Page com.zerock.apiserver.repository.search.Ex04_11_TodoSearch.search1(com.zerock.apiserver.dto.Ex04_7_PageRequestDto); Reason: Paging query needs to have a Pageable parameter; Offending method: public abstract org.springframework.data.domain.Page com.zerock.apiserver.repository.search.Ex04_11_TodoSearch.search1(com.zerock.apiserver.dto.Ex04_7_PageRequestDto) 2024-12-02T05:13:24.535+09:00 INFO 7780 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2024-12-02T05:13:24.537+09:00 INFO 7780 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2024-12-02T05:13:24.538+09:00 INFO 7780 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. 2024-12-02T05:13:24.539+09:00 INFO 7780 --- [ restartedMain] o.apache.catalina.core.StandardService : Stopping service [Tomcat] 2024-12-02T05:13:24.545+09:00 INFO 7780 --- [ restartedMain] .s.b.a.l.ConditionEvaluationReportLogger : Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 2024-12-02T05:13:24.556+09:00 ERROR 7780 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ex04_10_TodoServiceImpl' defined in file [C:\Users\hykim\Desktop\apiserver\build\classes\java\main\com\zerock\apiserver\service\Ex04_10_TodoServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'ex04_13_TodoRepository' defined in com.zerock.apiserver.repository.Ex04_13_TodoRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Could not create query for public abstract org.springframework.data.domain.Page com.zerock.apiserver.repository.search.Ex04_11_TodoSearch.search1(com.zerock.apiserver.dto.Ex04_7_PageRequestDto); Reason: Paging query needs to have a Pageable parameter; Offending method: public abstract org.springframework.data.domain.Page com.zerock.apiserver.repository.search.Ex04_11_TodoSearch.search1(com.zerock.apiserver.dto.Ex04_7_PageRequestDto) at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:795) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:237) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1375) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1212) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.15.jar:6.1.15] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971) ~[spring-context-6.1.15.jar:6.1.15] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-context-6.1.15.jar:6.1.15] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.3.6.jar:3.3.6] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.6.jar:3.3.6] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.6.jar:3.3.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.6.jar:3.3.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.6.jar:3.3.6]
안녕하세요 존경하는 토비님. 강의 너무 재밌게 보고 있습니다. 이번 강의(오브젝트와 의존관계)를 보다가 제가 지금까지 생각해왔던것과 다른부분이 있어서, 다르게 알고 있었다면 이번 기회에 다시 바르게 잡고 싶어서 질문을 올립니다. 오브젝트 = 클래스의 인스턴스 저는 지금까지 오브젝트를 조금 다르게 해석하고 있었습니다. 객체: 컴파일 시점의 타입 인스턴스: 런타임 시점의 타입 컴파일 시점에서는 객체는 참조하는 클래스 또는 인터페이스로 타입이 정해지지만, 다형성에 의해 런타임 시점에서는 참조하는 인스턴스로 정해진다고 생각했었습니다. 의존관계를 설정할때도, 코드를 작성할땐 (컴파일시점) 의존할 객체를 인터페이스/클래스로 참조하지만, 구현체(인스턴스)는 런타임 시점에 정의되므로, 인스턴스는 곧 런타임의 타입이라고.. 생각해왔습니다. 제가 객체와 인스턴스에 대해 잘못 생각하고 있었던걸까요? 바쁘시겠지만 시간되실때 조언 한마디 주시면 감사하겠습니다~~!
s.nextInt()로 int 값을 입력한 후 s.nextLine()으로 String 값을 입력하는 설명에서 제가 알고 있는 것과 달라서 질문 글을 남깁니다:) 10\nTEST\n 인 상황에서 s.nextInt()로 10과 \n을 읽고 그 다음 s.nextLine()으로 test와 \n을 읽는다고 설명을 해주셨습니다. import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("num: "); int num = sc.nextInt(); System.out.print("str: "); String str = sc.nextLine(); System.out.println(">> " + num + ", " + str); } } 하지만 위의 코드에서 생각한 결과와 조금 다른 결과가 나오는데요. 10을 입력하고 엔터를 누르면 sc.nextInt()에 의해 10은 num에 저장됩니다. 하지만 이때 \n은 버퍼에 그대로 남아있는 상태입니다. 이때 다음 코드로 sc.nextLine()을 호출하게되면 sc.nextLine()은 \n을 읽고 str에 저장을 해버려 저희가 의도한 상황과 조금 다른 결과가 나오게 됩니다. 그래서 항상 sc.nextInt() 등등과 같은 메서드를 호출한 다음에는 버퍼에 남아있는 \n을 날리는 용도의 sc.nextLine()을 호출해야하는 것으로 알고 있습니다. import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("num: "); int num = sc.nextInt(); sc.nextLine(); // 버퍼에 남아있는 \n 날리기(?) System.out.print("str: "); String str = sc.nextLine(); System.out.println(">> " + num + ", " + str); } } 아직 자바 공부에 대한 깊이가 부족하여 제가 이해한 것에 대한 설명이 적절한지 의문이 들지만 혹시 틀린 부분이 있다면 알려주세요:)
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 안녕하세요 김영한님 ! REQUIRES_NEW는 완전히 물리적으로 트랜잭션이 분리되어 REQUIRED(A 메서드)에서 REQUIRES_NEW(B 메서드)를 호출 했을 때 B 메서드에 발생한 예외가 A 메서드에 전파되지 않는다고 이해했습니다. 실제 확인을 위해 아래 코드를 구성해 @Service @RequiredArgsConstructor public class MeetingService { private final MeetingRepository meetingRepository; private final MemberService memberService; @Transactional public void save() { meetingRepository.save(new Meeting("스터디 모임", LocalDate.now(), LocalTime.now(), "AB3AS2EG")); memberService.save(); } @Transactional(readOnly = true) public List<Meeting> findAll() { return meetingRepository.findAll(); } } @Service @RequiredArgsConstructor public class MemberService { private final MemberRepository memberRepository; @Transactional(propagation = Propagation.REQUIRES_NEW) public void save() { memberRepository.save(new Member("김철수")); throw new IllegalArgumentException(); } @Transactional(readOnly = true) public List<Member> findAll() { return memberRepository.findAll(); } } 아래 테스트 코드로 테스트를 진행했습니다. @Test void test() { assertThatThrownBy(() -> meetingService.save()) .isInstanceOf(IllegalArgumentException.class); // 롤백 여부 확인 List<Meeting> meetings = meetingService.findAll(); List<Member> members = memberService2.findAll(); assertThat(meetings).isEmpty(); assertThat(members).isEmpty(); } 결과를 로그로 분석해보니 MemberService의 트랜잭션은 독립적으로 롤백 발생한 예외가 MeetingService로 전파 전파된 예외로 인해 MeetingService의 트랜잭션도 롤백 이런식으로 흐름이 진행됐습니다. 제가 추측하기로는 물리적으로 분리는 되어 있지만 하나의 스레드에서 생긴 커넥션이고 자바의 예외 전파 메커니즘에 따라 A 메서드에서 호출한 B 메서드의 예외가 A 메서드에 전파된 것이 아닌가 생각을 했는데요 REQUIRES_NEW 사용 시 예외가 전파 되지 않는다. 라고 이해를 했어서 제가 실험한 결과가 맞는지 간과한 부분이 있었던 것인지 궁금합니다 !
연관관계가 없는 조인에 대해 설명하신 부분에 대해 문의 드립니다. 보통 연관관계가 없다고 한다면 외래키로 연결되지 않는 두개의 테이블 이라고 생각할텐데 강의에서는 두 테이블 간 연관관계는 존재하고 연관관계의 컬럼으로 조인하는것이 아닌 , 다른 컬럼으로 조인하는것을 연관관계가 없는 조인이라고 설명하시는것 같아 혼동이 옵니다. 연관관계가 없는 조인 의 경우 두 테이블 간에 외래키가 없는경우에도 연관관계 없는 조인이 가능한건지 아니면 외래키는 있지만 외래키 조인이 아닌 다른 컬럼으로 조인할수 있는것을 연관관계가 없는 조인이라고 하시는건지 알려 주시면 감사하겠습니다.
안녕하세요 지식공유자님. 강의에서 JwtProvider 에 @Component 어노테이션을 선언하셔서 스프링이 관리하도록 의도하신 것 같습니다. 그런데, 함수에 static 을 모두 붙이시고, 사용하는 쪽에서는 bean 으로 등록 하지 않고 static util 처럼 사용하시는 것을 확인했습니다. 질문은 두가지 입니다. @Component 를 선언하셨음에도 static 메서드를 authService 에서 사용하신 이유가 있으신지. 빈으로 만들고서도 static 함수로 사용하는 것에 이점이 있는 것인지. 답변 부탁드리겠습니다. 감사합니다.
안녕하세요 이번에 강의를 들으면서 동시성 문제를 실제 프로젝트에서 해결해보자는 취지에 엔티티 설계에 대한 고민이 생겨 질문 드립니다! public class Item { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long no; // 상품 : 품목 = 1 : N @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "prod_no", nullable = false) private Product product; @Column(name = "thumbnail_img_url") private String thumbNailImgUrl; // 대표 이미지 경로 // 품목옵션에 대한 필드 리스트 @OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true) private List<ItemOption> itemOptions = new ArrayList<>(); private String code; // 품목코드 -> 상품코드 + 1 을 붙인 것 private String name; // 품목명 -> 옵션 그룹 + 옵션 값 @Column(name = "add_price", precision = 10, scale = 2) private Integer addPrice; // 추가금액 private Integer totalPrice; // 정상가격(원가) + 추가금액 private Integer qty; // 재고량 @Column(name = "saf_qty") private Integer safQty; // 안전재고량 @Enumerated(EnumType.STRING) private ProductSellingStatus sellingStatus; // 판매 상태 @Column(name = "max_qty") private Integer maxQty; // 최대 구매 수량 @Column(name = "min_qty") private Integer minQty; // 최소 구매 수량 } 현재 품목 엔티티라는 엔티티가 있습니다. 이 엔티티는 상품 + 옵션이 결합된 형태입니다. 그래서 재고 필드를 해당 엔티티에 정의 해주었습니다. 근데 여기서 들었던 의문점이 " 재고 엔티티를 따로 정의를 안해줘도 괜찮을까? " 라는 의문점이 들기 시작했습니다. 그래서 일단 확장성을 고려하지 않고 구현을 하게 된다면 이대로 품목 엔티티가 재고 필드를 가지고 있는 것도 괜찮을거 같다는 생각이 들었습니다. 하지만 확장성을 고려하게 된다면 재고 엔티티를 정의해 품목 엔티티와 일대일 관계를 갖도록 하는 것이 좋다고 생각하였습니다. " 확장성을 제외한 동시성 제어만을 고려했을 때 해당 설계도 괜찮을까? " 와 " 더 나은 설계는 무엇이 있을까? "에 대하여 조언을 듣고 싶습니다!!!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. @PatchMapping("/api/v2/members/{id}") public UpdateMemberResponse updateMember(@PathVariable("id") Long id, @RequestBody @Valid UpdateMemberRequest updateMemberRequest) { 수정 api는 위와 같은 주소를 이용합니다. 근데 사실 UpdateMemberRequest에 id라는 필드를 넣고 주소를 /api/v2/members 로 둬도 상관 없지 않나요? id를 PathVariable로 뺀 이유가 궁금합니다