@Entity public class Team { @Id @GeneratedValue @Column(name = "TEAM_ID") private Long id; private String name; @OneToMany(mappedBy = "team") private List<Member> members = new ArrayList<>(); // 아래는 getter, setter } @Entity public class Member { @Id @GeneratedValue @Column(name = "MEMBER_ID") private Long id; @Column(name = "USERNAME") private String username; @ManyToOne @JoinColumn(name = "TEAM_ID") private Team team; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Team getTeam() { return team; } public void setTeam(Team team) { this.team = team; } public void changeTeam(Team team){ this.team = team; //연관관계 편의 메소드 team.getMembers().add(this); } } public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); try { //저장 Team team = new Team(); team.setName("TeamA"); em.persist(team); Member member = new Member(); member.setUsername("member1"); //member.setTeam(team); //owner에 넣어야 DB 반영됨 member.changeTeam(team); //연관관계 편의 메소드 em.persist(member); Member member1 = new Member(); member1.setUsername("member2"); member1.changeTeam(team); em.persist(member1); em.flush(); em.clear(); Team findTeam = em.find(Team.class, team.getId()); List<Member> members = findTeam.getMembers(); System.out.println("====================="); for (Member m : members) { System.out.println("m = " + m.getUsername()); } System.out.println("====================="); tx.commit(); } catch (Exception e){ tx.rollback(); } finally { em.clear(); } emf.close(); } Team, Member가 양방향 연관관계를 맺고 있는 상태에서 우선 Team을 조회하고 Team의 members를 사용하는 시점에 Member를 조회하는 예시입니다. 처음에는 select m.team_id, m.member_id, m.username from member as m where member.team_id = 1; 이런 형태로 select 쿼리가 발생할 것으로 예상했습니다. 하지만 실제 hibernate로 발생한 쿼리를 확인하니 아래와 같은 쿼리가 발생했습니다. Hibernate: select members0_.TEAM_ID as team_id3_0_0_, members0_.MEMBER_ID as member_i1_0_0_, members0_.MEMBER_ID as member_i1_0_1_, members0_.TEAM_ID as team_id3_0_1_, members0_.USERNAME as username2_0_1_ from Member members0_ where members0_.TEAM_ID=? hibernate가 생성한 select쿼리에서 team_id, member_id 컬럼이 두번 나오는 이유가 무엇인가요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 영한님처럼 이렇게 나왔으면 하지만,, spring: #띄어쓰기 없음 datasource: #띄어쓰기 2칸 url: jdbc:h2:tcp://localhost/~/jpashop username: sa password: driver-class-name: org.h2.Driver jpa: #띄어쓰기 2칸 hibernate: #띄어쓰기 4칸 ddl-auto: create #띄어쓰기 6칸 properties: #띄어쓰기 4칸 hibernate: #띄어쓰기 6칸 format_sql: true # show_sql: true #띄어쓰기 8칸 logging: level: org.hibernate.sql: debug org.hibernate.orm.jdbc.bind: trace yml 설정이 이렇게 되있는데도 아래와 같이 나옵니다. 그리고 빨간 경고가 뜨는 이유는 뭔지 알 수 있을까요..? WARNING: A Java agent has been loaded dynamically (C:\...\.gradle\caches\modules-2\files-2.1\net.bytebuddy\byte-buddy-agent\1.14.10\90ed94ac044ea8953b224304c762316e91fd6b31\byte-buddy-agent-1.14.10.jar) WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information WARNING: Dynamic loading of agents will be disallowed by default in a future release ``` 부트 3.2버전에 JDK는 21로 설정했습니다. 혹시나 build.gradle 도 같이 올립니다. plugins { id 'java' id 'org.springframework.boot' version '3.2.0' id 'io.spring.dependency-management' version '1.1.4' } group = 'jbabook' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '21' } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-devtools' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() }
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 테이블 생성 제대로 되는 것 확인하였으나 sql문이 터미널에 나타나지 않습니다. 이전 강의 참고하여 repository를 인터페이스 상속받는 형태로 만들어보긴 했는데 이 부분은 문제 없을 것으로 생각됩니다. build.gradle plugins { id 'java' id 'org.springframework.boot' version '3.2.0' id 'io.spring.dependency-management' version '1.1.4' } group = 'jpabook' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '17' } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-devtools' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' //JUnit4 추가 testImplementation("org.junit.vintage:junit-vintage-engine") { exclude group: "org.hamcrest", module: "hamcrest-core" } } tasks.named('test') { useJUnitPlatform() } application.yml spring: datasource: url: jdbc:h2:tcp://localhost/~/databasesByH2/jpashop username: sa password: driver-class-name: org.h2.Driver jpa: hibernate: ddl-auto: create properties: hibernate: #show_sql: true format_sql: true logging.level: org.hibernate.orm.jdbc.bind: trace #스프링 부트 3.x, hibernate6 Member.java package jpabook.jpashop.entity; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import lombok.Getter; import lombok.Setter; @Entity @Getter @Setter public class Member { @Id @GeneratedValue private Long id; private String username; } MemberRepository.java (인터페이스) package jpabook.jpashop.repository; import jpabook.jpashop.entity.Member; public interface MemberRepository { public Long save(Member member); public Member find(Long id); } JpaMemberRepository.java (구현체) package jpabook.jpashop.repository; import jakarta.persistence.EntityManager; import jakarta.persistence.PersistenceContext; import jpabook.jpashop.entity.Member; import org.springframework.stereotype.Repository; @Repository public class JpaMemberRepository implements MemberRepository{ @PersistenceContext EntityManager em; @Override public Long save(Member member) { em.persist(member); return member.getId(); } @Override public Member find(Long id) { return em.find(Member.class, id); } } JpaMemberRepositoryTest.java package jpabook.jpashop.repository; import jpabook.jpashop.entity.Member; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.Rollback; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; import static org.junit.jupiter.api.Assertions.*; @RunWith(SpringRunner.class) @SpringBootTest class JpaMemberRepositoryTest { @Autowired MemberRepository memberRepository; @Test @Transactional @Rollback(false) void save() { //given Member member = new Member(); member.setUsername("조건우"); //when Long resultId = memberRepository.save(member); Member findMember = memberRepository.find(resultId); //then Assertions.assertThat(findMember.getUsername()).isEqualTo(member.getUsername()); Assertions.assertThat(findMember.getId()).isEqualTo(member.getId()); Assertions.assertThat(findMember).isEqualTo(member); } @Test void find() { } } JpaMemberRepositoryTest.java 실행로그 > Task :compileJava UP-TO-DATE > Task :processResources UP-TO-DATE > Task :classes UP-TO-DATE > Task :compileTestJava UP-TO-DATE > Task :processTestResources NO-SOURCE > Task :testClasses UP-TO-DATE 15:29:18.352 [Test worker] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [jpabook.jpashop.JpashopApplicationTests]: JpashopApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. 15:29:18.391 [Test worker] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration jpabook.jpashop.JpashopApplication for test class jpabook.jpashop.JpashopApplicationTests 15:29:18.451 [Test worker] INFO org.springframework.boot.devtools.restart.RestartApplicationListener -- Restart disabled due to context in which it is running . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.2.0) 2023-12-18T15:29:18.567+09:00 INFO 2911 --- [ Test worker] j.jpashop.JpashopApplicationTests : Starting JpashopApplicationTests using Java 17.0.9 with PID 2911 (started by kangg in /Users/kangg/Coding/jpashop) 2023-12-18T15:29:18.568+09:00 INFO 2911 --- [ Test worker] j.jpashop.JpashopApplicationTests : No active profile set, falling back to 1 default profile: "default" 2023-12-18T15:29:18.865+09:00 INFO 2911 --- [ Test worker] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode. 2023-12-18T15:29:18.875+09:00 INFO 2911 --- [ Test worker] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 6 ms. Found 0 JPA repository interfaces. 2023-12-18T15:29:19.077+09:00 INFO 2911 --- [ Test worker] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default] 2023-12-18T15:29:19.097+09:00 INFO 2911 --- [ Test worker] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.3.1.Final 2023-12-18T15:29:19.111+09:00 INFO 2911 --- [ Test worker] o.h.c.internal.RegionFactoryInitiator : HHH000026: Second-level cache disabled 2023-12-18T15:29:19.201+09:00 INFO 2911 --- [ Test worker] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer 2023-12-18T15:29:19.213+09:00 INFO 2911 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... 2023-12-18T15:29:19.245+09:00 INFO 2911 --- [ Test worker] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:tcp://localhost/~/databasesByH2/jpashop user=SA 2023-12-18T15:29:19.246+09:00 INFO 2911 --- [ Test worker] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. 2023-12-18T15:29:19.542+09:00 INFO 2911 --- [ Test worker] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration) 2023-12-18T15:29:19.554+09:00 INFO 2911 --- [ Test worker] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default' 2023-12-18T15:29:19.634+09:00 WARN 2911 --- [ Test worker] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning 2023-12-18T15:29:19.643+09:00 INFO 2911 --- [ Test worker] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: class path resource [static/index.html] 2023-12-18T15:29:19.812+09:00 INFO 2911 --- [ Test worker] j.jpashop.JpashopApplicationTests : Started JpashopApplicationTests in 1.367 seconds (process running for 1.814) OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended 2023-12-18T15:29:20.098+09:00 INFO 2911 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2023-12-18T15:29:20.099+09:00 INFO 2911 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2023-12-18T15:29:20.104+09:00 INFO 2911 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. > Task :test Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. For more on this, please refer to https://docs.gradle.org/8.5/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. BUILD SUCCESSFUL in 2s 4 actionable tasks: 1 executed, 3 up-to-date 3:29:20 PM: Execution finished ':test --tests "jpabook.jpashop.JpashopApplicationTests"'.
아래와 같은 에러가 발생하여 application.properties 를 application.yml로 바꾸어봤지만 같은에러가납니다. *************************** APPLICATION FAILED TO START *************************** Description: Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class Action: Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active). 아래 코드는 application.yml내용입니다. spring: datasource: driver-class-name: org.mariadb.jdbc.Driver url: jdbc:mariadb://localhost:3306/apidb username: apidbuser password: apidbuser jpa: hibernate: ddl-auto: update properties: hibernate: format_sql: true show-sql: true logging: level:debug 아래코드는 build.gradle 내용입니다. buildscript { ext { queryDslVersion = "5.0.0" } } plugins { id 'java' id 'org.springframework.boot' version '3.0.13' id 'io.spring.dependency-management' version '1.1.4' } group = 'org.mail' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '17' } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' testCompileOnly'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'org.mariadb.jdbc:mariadb-java-client' annotationProcessor 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta" annotationProcessor( "jakarta.persistence:jakarta.persistence-api", "jakarta.annotation:jakarta.annotation-api", "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta") } tasks.named('bootBuildImage') { builder = 'paketobuildpacks/builder-jammy-base:latest' } tasks.named('test') { useJUnitPlatform() } compileJava.dependsOn('clean') 맨위에 에러 난 후 이하 반복적인 에러가 발생하지만 값을 가져오는데는 이상이없습니다. 프론트에서 호출해도 정상적으로 데이터가 호출됩니다. 그래서 quertdsl에 관한내용을 지우고 해봤는데 에러가 사라졌습니다. 혹시 querydsl 에 관한 이슈가 있는걸까요? 검색을 해봤지만 발견할 수가 없었습니다. java.lang.NullPointerException: Cannot read field "generatedClass" because "data" is null
안녕하세요! 어쩌면 간단한 질문일 수도 있겠습니다만, 좀 헷갈려서 여쭤봅니다. 양방향 연관관계를 맺어줄 때, 순수한 객체 관계를 고려하면 항상 양쪽다 값을 입력해야 한다고 강의에서 봤습니다. 그래서 연관관계 편의 메소드도 생성하고요. 그런데 문득 궁금해졌습니다. 서로 관계를 맺어준 객체들은 어차피 해당 메소드가 종료되면 사라지지 않나요? 결국 DB에 외래키를 가진 테이블 연관관계로만 존재할텐데, 곧 소멸될(?) 객체끼리의 참조 관계 설정을 왜 해줘야 하나 궁금합니다. 예를 들어 memberA에게 Team1의 참조 연관관계를 맺어준다고 해도 메소드가 종료되면 그 객체의 관계는 DB 테이블로만 남게 되니 아무 소용이 없지 않나 생각이 들었습니다. 혹시 해당 요청 내의 메소드 안에서 수월한 비즈니스 로직 처리를 위해 일회성으로 객체끼리 참조 연관관계를 맺어주는 걸까요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 예제 도메인 모델과 동작확인 강의에서 8:55분에 보면 연관 관계를 위해서 changeTeam이라는 메소드를 생성하시는데 해당 코드에서 team.getMembers().add(this)라는 코드가 있는데 해당 코드가 없어도 동작에 아무 이상이 없고 또한 Member에서 getMembers를 출력해보거나 DB를 보아도 달라진게 하나도 없는데 해당 라인의 코드를 적는 이유를 모르겠습니다. 만약 이유가 있다면 확인할만한 방법이 뭐가 있을까요?
자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
먼저 대출 기능 만들기 강의를 듣다가 문제를 2개 발견하였습니다. 유저 등록부터 'java.lang.IllegalArgumentException: null' 가 생깁니다.... 진짜 전에 잘 되던 것이 갑자기 왜 안되는지 막막합니다.... 그리고 대출 기능도 'java.lang.IllegalArgumentException: null' 가 생깁니다....이건 혹시 유저 부분에서 등록이 안되는 부분 때문에 생기는 오류인건지...부탁드립니다.. 똑같이 대출 기능 만들기 부분에서 생기는 건데, 위의 오류 문제를 해결하려고 형변환을 없애다 보니 아래와 같이 빨간줄이 나옵니다.. 왜 이러는 걸까요...ㅠㅠ 구글 링크로 파일 업로드 했으니, 혹시나 참고해서 말씀하실 부분 있으시면 말씀 부탁드립니다. https://drive.google.com/file/d/1X9s-VjcAeBurdxOYrIOzwa0yZNNoue54/view?usp=sharing https://drive.google.com/drive/folders/1vB-XwaSlIKfY2Diq66g6JnQ8vyKVWQvn?usp=sharing
테스트 코드를 실행시키면 org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement [Sequence "MEMBER_SEQ" not found; SQL statement: select next value for member_seq [90036-224]] [select next value for member_seq]; SQL [select next value for member_seq] 오류가 발생합니다. H2 에서 직접 CREATE SEQUENCE 쿼리로 직접 생성하고 나니까 테스트가 동작하네요 .. ddl-auto: create 확인했고 띄어쓰기 두칸 아닌것도 확인 했는데요 ,, 왜 안되는거죠?
JpaRepository나 PageRepository 등 불필요한 쿼리도 자동으로 만들어주더라구요 그래서 해당 레포지토리에서 직접 정의한 메소드 말고는 막고 생성하고 싶지 않다면 어떤 방법을 사용하시나요? 디버깅하다보니 Repository.class 인터페이스와 어노테이션인 RepositoryDefinition.class를 필터로 스캔하는 걸 확인했습니다. RepositoryDefinition를 사용하는 것보다 직접 정의해서 사용할 생각이면 Repository.class만 상속해서 사용하시나요 ?
public List<OrderQueryDto> findAllByDto_optimization() { List<OrderQueryDto> result = findOrders(); List<Long> orderIds = result.stream() .map(o -> o.getOrderId()) .collect(Collectors.toList()); List<OrderItemQueryDto> orderItems = em.createQuery( "select new jpabook.jpashop.repository.order.query.OrderItemQueryDto(oi.order.id, i.name, oi.orderPrice, oi.count)" + " from OrderItem oi" + " join oi.item i" + " where oi.order.id in :orderIds", OrderItemQueryDto.class) .setParameter("orderIds", orderIds) .getResultList(); //최적화(Lambda사용) Map<Long, List<OrderItemQueryDto>> orderItemMap = orderItems.stream() .collect(Collectors.groupingBy(orderItemQueryDto -> orderItemQueryDto.getOrderId())); result.forEach(o -> o.setOrderItems(orderItemMap.get(o.getOrderId()))); return result; } 여기서 map을 사용하는 코드가 있는 경우에는 쿼리를 한 번 날리고 map으로 가져와서 값을 세팅하기 때문에 쿼리가 총 2번 나가는 거고 그 부분이 없으면 어떤 방식으로 쿼리가 나가는 건가요?
강의를 듣다보니 Api를 사용하기 위해 만든 Controller에서는 @Transactional 어노테이션이 포함된 Service를 아예 사용 안해서 트랜잭션의 시작을 어디로 봐야 될지 모르겠어서요 1.@Transactional 어노테이션을 달고있는 메서드의 시작이 트랜잭션의 시작이고, 또한 em를 통해서 createQuery나 persist를 하는 것은 em코드가 포함된 메서드가 트랜잭션의 시작인건가요? 2.그리고 컨트롤러는 컨트롤러에 남겨두고 내부 로직이 있으면 빼내서 클래스로 만들어서 @Transactional(readOnly = true)로 설정해서 컨트롤러에서 쓰면 컨트롤러는 그대로 있고, 내부의 로직을 트랜잭션 어노테이션으로 묶는건가요? 3.2번이 맞게 이해한거면 ApiController에 있는 컨트롤러에 바로 @Transactional을 붙이면 OSIV를 꺼도 작동되는데 이렇게 컨트롤러에 바로 붙이면 OSIV를 킨거와 같은 경우가 되는거 아닌가요?
[질문 내용] JPA와 SPRING DATA JPA 모두 동적 쿼리 작성에 문제에 어려움이 있었고 이를 위해 querydsl을 적용하는것이기에 무의식적으로 JpaItemRepositoryV2를 복사해서 동적 쿼리 작성하는 부분만 변경하려했습니다. 테스트는 잘통과합니다만 위와 같이 JPAQueryFactory를 빈으로 등록하고 사용하는 것이 맞는걸까요? 아직 빈 등록 및 의존관계 주입하는 게 익숙치 않아서 스스로 확신이 안듭니다. 위 코드에서 빈으로 등록하고 주입되는 과정은 나름 알고있으나 좀 더 구조적?으로 개선될 방향이 있는지 궁금합니다.(문법적으론 문제가 없으나 이렇게 하면 더 좋다) 감사합니다
4개의 테이블 (a, b, c, d) 각각 1:N 관계 입니다. a-b 1:N, b-c 1:N , c-d 1:N (fetchType = LAZY) 네개의 테이블에 대한 정보를 fetchjoin을 통해서 List<a> 객체로 리턴 받았습니다. List<a> 객체를 루프를 돌면서 a 객체 값에 특정 필드를 변경하고 .save()를 호출 했더니 update 쿼리만 나가는게 아니고 1) a 테이블의 id(pk)값의 조건 select 쿼리 1회 2) b 테이블 조건절에는 id(FK) select 쿼리 1회 3) 위에서 값이 조회될경우 c테이블에 b테이블 결과 id(PK) 값들로 IN 쿼리 1회 4) d 테이블 3)과 동일한 구조로 IN쿼리 1회 5) 최종 udpate 쿼리 호출 이런식의 마치 해당 a 객체 전체 데이터(하위 포함)를 조회 했을떄 날라가는 select쿼리가 모두 호출 되었습니다. 예) List<a> result = aRepository.getFetchJoinQuery(); result.stream ().forEach(a -> { a.setName("HOON"); aRepository.save (a); -> 해당 시점 위 쿼리 호출됨 logger.info("xxxxxx"); }); 디버깅으로 확인한 내용이구요, 혹시나 디버깅 모드에서 데이터 확인중에 날아간 쿼리인가 해서 디버깅없이 RUN으로 실행했을때도 동일하게 쿼리가 발생하는것이 확인 되었습니다.. save() 사용시에 select 쿼리 발생은 어쩔수 없는걸까요? 어쩔수 없다면 save() 메서드 대신 그냥 JPQL로 update 쿼리를 작성해서 사용하는 방법뿐이 없을까요? 궁금합니다!
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? ( 예 /아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? ( 예 /아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? ( 예 /아니오) [질문 내용] 섹션4. 엔티티 매핑 -44p "참조가 없으므로 UML도 잘못됨" UML은 찾아보니 특정한 다이어그램들을 나타내는 것 같은데, 참조가 없는것과 UML은 무슨 연관이 있으며, 이로인해 UML이 잘못되었다는게 어떤 의미인지 이해가 되지 않습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 안녕하세요. 테스트케이스 recoverException_fail 를 실행했을때 테스트가 실패하여 질문 남깁니다. 해당 테스트 케이스를 실행하면 실패 로그가 나오고 java.lang.Exception: exception just for purpose of providing stack trace at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.markRollbackOnly( JdbcResourceLocalTransactionCoordinatorImpl.java:310 ) ~[ hibernate-core-6.3.1.Final .jar: 6.3.1.Final ] java.lang.AssertionError: Expecting actual throwable to be an instance of: org.springframework.transaction.UnexpectedRollbackException but was: java.lang.RuntimeException at hello.springtx.propagation.LogRepository.save(LogRepository.java:26) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ...(108 remaining lines not displayed - this can be changed with Assertions.setMaxStackTraceElementsDisplayed) at hello.springtx.propagation.MemberServiceTest.recoverException_fail(MemberServiceTest.java:135) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) UnexpectedRollbackException 을 기대하지만 RuntimeException가 나온다고 메세지가 나오는데 설명 해주신 대로면 UnexpectedRollbackException 예외가 나오는게 맞는거 아닌가요..?