월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨실전! 스프링 데이터 JPA
스프링 부트3와 카운트 쿼리 분리
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요.카운트 쿼리 분리 부분을 듣는 도중에 카운트 쿼리에 LEFT JOIN이 사용되는 결과를 확인하기 위해 다음처럼 코드를 작성하였습니다.public interface MemberRepository extends JpaRepository<Member, Long> { @Query(value = "select m from Member m left join m.team t") Page<Member> findByAge(int age, Pageable pageable); ... } @Test public void paging() throws Exception { //given memberRepository.save(new Member("member1", 10)); memberRepository.save(new Member("member2", 10)); memberRepository.save(new Member("member3", 10)); memberRepository.save(new Member("member4", 10)); memberRepository.save(new Member("member5", 10)); //when PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.ASC, "username")); Page<Member> page = memberRepository.findByAge(10, pageRequest); //then List<Member> content = page.getContent(); assertThat(content.size()).isEqualTo(3); assertThat(page.getTotalElements()).isEqualTo(5); assertThat(page.getNumber()).isEqualTo(0); assertThat(page.getTotalPages()).isEqualTo(2); assertThat(page.isFirst()).isTrue(); assertThat(page.hasNext()).isTrue(); }그런데 결과는 강의와는 달리 카운트 쿼리에 LEFT JOIN 이 사용되지 않았고, 심지어 JPQL select m from Member m left join m.team t 을 @Query에 작성했음에도 조회 쿼리도 LEFT JOIN을 사용하지 않은 것을 확인했습니다.이후 스프링 부트 3 이하 버전에서 동일한 코드로 실행해보니 강의와 동일한 결과를 얻을 수 있었습니다.스프링 부트 3 부터 적용된 스프링 데이터 JPA 에서는 이러한 부분의 최적화를 자동으로 제공하는 것일까요?
- 해결됨실전! 스프링 데이터 JPA
Spring Data JPA 페이징과 default_batch_fetch_size
JPA에서 컬렉션 조회와 페이징을 함께 사용하려면ToOne (OneToMany, OneToOne) 관계를 모두 페치 조인하고, 지연 로딩 성능 최적화를 위해 hibernate.default_batch_fetch_size 옵션을 적용해야 한다.라고 배웠었는데 이 내용이 Spring Data JPA에서도 컬렉션을 조회하면서 페이징 관련된 Pageable, Page 등을 사용하기 위해서는default_batch_fetch_size 를 적용해줘야 하는 거죠??
- 해결됨실전! 스프링 데이터 JPA
단건 조회 처리 방식에 대해
단건 조회는 결과가 없을 경우 예외 발생 대신 null을 반환한다고 하였는데이 null을 어떤 방식으로 처리하는게 좋은 방법인가 싶어 질문 드립니다.질문 드리고 싶은 방법은 아래와 같이 2가지입니다.둘 중 어느 방식을 사용하는게 더 좋을까요? if문을 통해 null일 시에 런타임 예외 터트리기Member member = memberRepository.findById(10L) if (member == null) { throw new CustomException("찾고자 하는 멤버가 없습니다."); } 반환 타입을 Optional로 감싸 반환하기.Optional<Member> member = memberRepository.findById(10L).orElseThrow(() -> new CustomException("찾고자 하는 멤버가 없습니다."));
- 미해결실전! 스프링 데이터 JPA
NoSuchElementException: No value present 오류가 납니다ㅠㅠ
@RequiredArgsConstructor @RestControllerpublic class MemberController { private final MemberRepository memberRepository; @GetMapping("/members/{id}") public String findMember(@PathVariable("id") Long id) { Member member = memberRepository.findById(id).get(); return member.getUsername(); } public void init() { memberRepository.save(new Member("userA")); } 2023-06-17T14:29:55.066+09:00 DEBUG 6856 --- [nio-8080-exec-1] org.hibernate.SQL :selectm1_0.member_id,m1_0.age,m1_0.created_by,m1_0.created_date,m1_0.last_modified_by,m1_0.last_modified_date,m1_0.team_id,m1_0.usernamefrommember m1_0wherem1_0.member_id=?2023-06-17T14:29:55.068+09:00 INFO 6856 --- [nio-8080-exec-1] p6spy : #1686979795068 | took 0ms | statement | connection 4| url jdbc:h2:tcp://localhost/~/datajpaselect m1_0.member_id,m1_0.age,m1_0.created_by,m1_0.created_date,m1_0.last_modified_by,m1_0.last_modified_date,m1_0.team_id,m1_0.username from member m1_0 where m1_0.member_id=?select m1_0.member_id,m1_0.age,m1_0.created_by,m1_0.created_date,m1_0.last_modified_by,m1_0.last_modified_date,m1_0.team_id,m1_0.username from member m1_0 where m1_0.member_id=1;2023-06-17T14:29:55.071+09:00 INFO 6856 --- [nio-8080-exec-1] p6spy : #1686979795071 | took 0ms | commit | connection 4| url jdbc:h2:tcp://localhost/~/datajpa;2023-06-17T14:29:55.074+09:00 ERROR 6856 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.util.NoSuchElementException: No value present] with root causejava.util.NoSuchElementException: No value presentat java.base/java.util.Optional.get(Optional.java:143) ~[na:na]at study.datajpa.constoller.MemberController.findMember(MemberController.java:18) ~[classes/:na]at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) ~[spring-web-6.0.9.jar:6.0.9]at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) ~[spring-web-6.0.9.jar:6.0.9]at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.0.9.jar:6.0.9]at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) ~[spring-webmvc-6.0.9.jar:6.0.9] http://localhost:8080/members/1에 userA가 나와야 하는데 Whitelabel Error Page가 뜨고 위와 같은 오류가 나옵니다.
- 해결됨실전! 스프링 데이터 JPA
dto와 영속성 관리
안녕하세요 스프링 부트 시리즈를 거의 다 들었는데요,엔티티를 영속성 컨텍스트에서 관리하면 1차 캐시가 생겨서 2번째 조회할 때는 db가 아니라 영속성 컨텍스트에서 가져온다고 알고있는데요그래서 공부하면서 스프링 데이터 jpa랑 querydsl로 회원 조회, 수정, 삭제 등 공부하면서 api 호출로 값을 받을 때 dto를 통해서 받는 로직을 짜고 테스트를 했습니다.member1을 읽은 뒤에 db에서 강제로 이름을 member2로 바꾸고 다시 호출했는데 member2로 잘 읽어 오더라고요 member1을 읽어와서 영속성 컨텍스트에 이미 올라있는 정보를 바로 가져올 줄 알았는데 제 예상이 틀렸습니다.이게 엔티티를 직접 조회한게 아니라 dto를 통해 조회해서 그런건가요? 아니면 혹시 제가 뭘 잘못알고 있는 걸까요?
- 미해결실전! 스프링 데이터 JPA
h2 데이터 베이스 연결하는데 오류가 있습니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]h2 데이터베이스를 연결하는 도중에 오류가 발생해서 질문드립니다 처음에 jdbc:h2:~/datajpa 이렇게 해서 연결을 성공해서 jdbc:h2:tcp://localhost/~/datajpa 이렇게 url을 입력을 해서 진행을 했는데 connen timed out이 발생을 합니다 datajpa.mv.db 생성된것도 확인을 하고 gitbash로 권한도 바꿔줬습니다!
- 미해결실전! 스프링 데이터 JPA
06:25~07:05 강의 내용 관련 디버깅 하다가 질문 있습니다
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]안녕하세요! 강의 잘 듣고 있습니다.06:25~ 07:05 에서 설명하신 내용을 좀 더 파보기 위해서, 코드를 디버깅 하는 과정에서, 질문이 있습니다.(질문하고자 한 배경이 길어서, 질문의 내용은 맨 마지막에 있습니다!) => 설명해주신 내용을 제가 이해한 대로 적자면, "스프링 데이터 jpa는 NoResultException을 try-catch로 처리해서 null로 반환한다" 라고 이해했습니다.=> 그래서, 위 사진에서 breakPoint를 걸어서 F7로 저 메서드 내부를 파니까, 아래의 결과에서 해답이 있음을 유추했습니다=> 사진에서 retVal이 결국 null 값이며, 따라서 breakPoint인 retVal = invocation.proceed();에서, 강사님이 말씀해주신 "예외 처리 코드"가 있을 것이라고 생각했습니다. (질문)그런데 제가 위 breakPoint의 메서드를 F7로 들어가서 확인했는데 예외처리 코드 관련 부분이 어느 부분인지 잘 몰라서... 해당 부분을 어떻게 debugging으로 잡아낼 수 있을 지 문의드립니다.
- 해결됨실전! 스프링 데이터 JPA
DDD 적용시 JPA 설계에 대해 궁금한 사항
안녕하십니까 강사님. 좋은 강의 정말 감사합니다.이번에 강사님께 강의를 듣고 현업에 적용하는 도중 궁금한 사항이 있어 문의하게 되었습니다.저희는 현재 DDD 를 적용하려고 합니다. DDD 에서는 애그리거트끼리의 관계를 맵핑하는 것을 지양하는 것으로 알고 있습니다. 따라서 저희는 ERD 기준으로 도메인을 설계해보니 실제 나온 도메인을 보면 테이블이 전부 도메인 클래스가 되었고 서로간의 관계를 코딩으로 맺는 부분 (@ManyToOne 등)이 존재 하지 않습니다.현업에서도 ERD 를 기준으로 도메인 클래스를 나누면 테이블 당 하나의 애그리거트가 나오는 것이 보편적인 사항일까요?DDD 로 개발하다보면 도메인 클래스에 관계를 맺는 부분이 없는게 보편적일까요?
- 미해결실전! 스프링 데이터 JPA
Spring Data JPA delete 관련 질문
제가 따로 구현하지 않고Spring Data JPA JpaRepository 에서 상속받은deleteById 를 사용하면먼저 select query 가 1번 나간 다음에 찾아온 Entity로 delete 메서드를 호출하는 것 같더라구요그래서 총 select, delete 쿼리가 각각 1번 총 2번 나가는 것 같은데 PK로 delete 를 하고 싶을 때,@Query로 작성하여 delete 문을 1번 나가게 하는 것과,위의 방법대로 select, delete 각각 1번 나가는 방법 중에 어떤 방법을 사용하는 것이 좋은가요 ?
- 미해결실전! 스프링 데이터 JPA
페이지를 유지하면서 엔티티를 DTO로 변환관련하여 질문
스프링 데이터 JPA 페이징과 정렬 강의 부분에서페이지를 유지하면서 엔티티를 DTO로 변환하기Page<Member> page = memberRepository.findByAge(10, pageRequest); Page<MemberDto> dtoPage = page.map(m -> new MemberDto());페이지를 유지하면서 엔티티를 DTO로 변환하는 예제가 있습니다.만약에 아래와 같이 Page<Member> page = memberRepository.findByAge(10, pageRequest); List<Member> dtoPage = faqListPage.stream().map(MemberDto::new) .toList();List<> 로 반환하여 페이징 처리를 하였는데 페이지를 유지한 첫번째 방식 차이점이 있을까요??실무에서는 어떤 방식을 사용하나요?
- 해결됨실전! 스프링 데이터 JPA
[스프링 데이터 JPA 페이징과 정렬] left join 쿼리
MemberRepositorypublic interface MemberRepository extends JpaRepository<Member, Long> { List<Member> findMemberByUsernameAndAgeGreaterThan(String username, int age); ... @Query(value = "select m from Member m left join m.team t", countQuery = "select count(m.username) from Member m") Page<Member> findByAge(int age, Pageable pageable); } MemberRepositoryTestpackage hello.datajpa.repository; ... @SpringBootTest @Transactional @Rollback(false) class MemberRepositoryTest { @Autowired MemberRepository memberRepository; @Autowired TeamRepository teamRepository; ... @Test public void paging() { for (int i = 1; i <= 5; i++) { Member member = new Member("member" + i, 10); memberRepository.save(member); } int age = 10; PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username")); Page<Member> page = memberRepository.findByAge(age, pageRequest); List<Member> content = page.getContent(); long totalElements = page.getTotalElements(); int totalPages = page.getTotalPages(); int currentPage = page.getNumber(); boolean isFirst = page.isFirst(); boolean hasNext = page.hasNext(); assertThat(content.size()).isEqualTo(3); assertThat(totalElements).isEqualTo(5); assertThat(totalPages).isEqualTo(2); assertThat(currentPage).isEqualTo(0); assertThat(isFirst).isTrue(); assertThat(hasNext).isTrue(); } } Memberpackage hello.datajpa.entity; ... @Entity @Getter @Setter @NoArgsConstructor(access = AccessLevel.PROTECTED) @ToString(of = {"id", "username", "age"}) /*@NamedQuery( name = "Member.findByUsername", query = "select m from Member m where m.username = :username" )*/ public class Member { @Id @GeneratedValue @Column(name = "member_id") private Long id; private String username; private int age; @ManyToOne(fetch = LAZY) @JoinColumn(name = "team_id") private Team team; public Member(String username, int age) { this.username = username; this.age = age; } public Member(String username, int age, Team team) { this.username = username; this.age = age; changeTeam(team); } public void changeTeam(Team team) { if (team == null) throw new RuntimeException("Member.changeTeam: team is null"); this.team = team; team.getMembers().add(this); } } 쿼리select m1_0.member_id, m1_0.age, m1_0.team_id, m1_0.username from member m1_0 order by m1_0.username desc offset ? rows fetch first ? rows only select count(m1_0.username) from member m1_0강의와 다르게 left join을 해도 left join 관련 쿼리가 나가지 않는데 뭔가 강의와 다르게 설정된 부분이 있는 걸까요?@SpringBootTest @Transactional @Rollback(false) class MemberRepositoryTest { @Autowired MemberRepository memberRepository; @Autowired TeamRepository teamRepository; ... @Test public void paging() { Team team = new Team("A"); teamRepository.save(team); for (int i = 1; i <= 5; i++) { Member member = new Member("member" + i, 10); member.changeTeam(team); memberRepository.save(member); } int age = 10; PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Sort.Direction.DESC, "username")); Page<Member> page = memberRepository.findByAge(age, pageRequest); List<Member> content = page.getContent(); assertThat(team).isSameAs(content.get(0).getTeam()); // team == content.get(0).getTeam() ? long totalElements = page.getTotalElements(); int totalPages = page.getTotalPages(); int currentPage = page.getNumber(); boolean isFirst = page.isFirst(); boolean hasNext = page.hasNext(); assertThat(content.size()).isEqualTo(3); assertThat(totalElements).isEqualTo(5); assertThat(totalPages).isEqualTo(2); assertThat(currentPage).isEqualTo(0); assertThat(isFirst).isTrue(); assertThat(hasNext).isTrue(); } } 테스트 코드를 위와 같이 변경했을 때 left join 쿼리나 select 쿼리가 나가지 않고 assertThat(team).isSameAs(content.get(0).getTeam()) 테스트는 통과됩니다.위 코드는 이런 식으로 동작하는게 맞을까요?fetch join이 아니기 때문에 하이버네이트는 일단 member만 가져오는 쿼리를 날리고 레코드를 받아온다.받아온 레코드와 영속성 컨텍스트를 비교한다.받아온 레코드가 영속성 컨텍스트에 엔티티로 존재하므로 영속성 컨텍스트에 있는 엔티티를 반환한다.따라서 조회한 content.get(0) 객체에는 team 필드가 이미 할당 되어 있다.
- 미해결실전! 스프링 데이터 JPA
h2 데이터베이스 관련 문제
1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]질문 1)실전 스프링 Data JPA -섹션 1. 프로젝트 환경설정 -스프링 데이터 JPA와 DB설정, 동작확인 강의에서H2 데이터베이스 설치 후 , 동일하게 memberJpaRepositoryTest 한 후H2 데이터베이스 다시 접속하여 확인하여도 , member table 이 생성되어 있지 않습니다.콘솔창에 찍히는걸 봤을때는 insert까지 잘 된것을 확인했습니다만무엇이 문제일까요?[Member ].classpackage com.example.datajpa.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import lombok.Getter; @Entity @Getter public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) private Long id; private String name; public Member(String name) { this.name = name; } //디폴트값으로 private 하기엔 프록시 생성시 사용되어야 함으로 protected 제어자를 통해 다른곳에서 만들지 못하도록함 protected Member() { } } [MemberJpaRepository] .class@Repository public class MemberJpaRepository { @PersistenceContext private EntityManager em; //jpa의 영속성컨텍스트를 관리 하는 엔티티메니저, 이것에 의해 데이터를 관리함. public Member save(Member member ){ em.persist(member);// 영속화 return member; } public Member find(Long id){ return em.find(Member.class,id); } }[MemberJpaRepositoryTest] .class@SpringBootTest @Transactional // 테스트가 끝난후 데이터를 롤백하기 위해 @Rollback(false) // 만약 롤백을 원하지 않을경우엔 이 어노테이션을 사용함, 실전에서는 ! 사용 노노! class MemberJpaRepositoryTest { @Autowired MemberJpaRepository memberJpaRepository; @Test public void testMember(){ //public 생략가능 Member member = new Member("memberA"); Member savedMember = memberJpaRepository.save(member); Member findMember = memberJpaRepository.find(savedMember.getId()); assertThat(findMember.getName()).isEqualTo(member.getName()); assertThat(findMember.getId()).isEqualTo(member.getId()); assertThat(findMember).isEqualTo(member); } } [application.yml]spring: datasource: url: jdbc:h2:tcp://localhost/~/datajpa username: sa password: driver-class-name: org.h2.Driver jpa: hibernate: ddl-auto: create # 객체를 보고 자동으로 테이블 생성 여부. 생성 - create, 비생성 - none # 테스트이기 때문에 create로 설정하며 # 실제로는 none 으로 합니다. create이면 기존의 테이블을 전부 밀어버립니다. properties: hibernate: show_sql: true format_sql: true logging.level: org.hibernate.SQL: debug # 콘솔창에 파라미터 값을 보고 싶을때 주로 개발할때, 실전에서는 성능저하 가능성 고려하여 사용해야함. org.hibernate.type: trace #implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.7' 외부라이브러리 추가하면깔끔하게 파리미터값을 보여준다. # show_sql : 옵션은 System.out 에 하이버네이트 실행 SQL을 남긴다. # org.hibernate.SQL : 옵션은 logger를 통해 하이버네이트 실행 SQL을 남긴다. [build gradle]dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' //h2사용 runtimeOnly 'com.h2database:h2' [콘솔창]insert into member (id, name) values (default, ?) insert into member (id, name) values (default, 'memberA'); 2023-05-26 18:33:03.071 INFO 3250 --- [ main] p6spy : #1685093583071 | took 0ms | commit | connection 4| url jdbc:h2:mem:ca9facbe-0495-462f-a2eb-d8f9f1d14ecd ; 2023-05-26 18:33:03.072 INFO 3250 --- [ main] o.s.t.c.transaction.TransactionContext : Committed transaction for test: [DefaultTestContext@3b0c9195 testClass = MemberJpaRepositoryTest, testInstance = com.example.datajpa.repository.MemberJpaRepositoryTest@3f6a9ba0, testMethod = testMember@MemberJpaRepositoryTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@366c4480 testClass = MemberJpaRepositoryTest, locations = '{}', classes = '{class com.example.datajpa.DataJpaApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@5c86dbc5, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@5f9edf14, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@a8ef162, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@78fa769e, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@536dbea0, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@6b26e945], 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.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]] 2023-05-26 18:33:03.096 INFO 3250 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2023-05-26 18:33:03.097 INFO 3250 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down' 2023-05-26 18:33:03.101 INFO 3250 --- [ionShutdownHook] p6spy : #1685093583101 | took 2ms | statement | connection 5| url jdbc:h2:mem:ca9facbe-0495-462f-a2eb-d8f9f1d14ecd drop table if exists member CASCADE drop table if exists member CASCADE ; 2023-05-26 18:33:03.106 INFO 3250 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2023-05-26 18:33:03.115 INFO 3250 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. Process finished with exit code 0 질문 2. 이 강의를 보기 전에는 h2데이터베이스 별도 설치 없이아래와 같이 Application.yml 설정과Build.gradle에 의존성만 지정하여브라우저에서 Localhost:8080/h2-console 치면 h2 데이터베이스를 사용할 수 있었습니다.하지만 이 강의를 따라 h2 설치 후엔 Localhost:8080/h2-console 해도 500에러만 발생합니다. 이유가 뭘까요 ㅠㅠ[application.yml]# h2 datasource: driver-class-name: org.h2.Driver url: jdbc:h2:mem:db;MODE=MYSQL; username: sa password:[build gradle]dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' //h2사용 runtimeOnly 'com.h2database:h2'
- 미해결실전! 스프링 데이터 JPA
select 절에 조건식을 넣는 방법
강사님, 궁금한게 있습니다.select 절에 조건식을 넣고 싶은데 어떻게 해야 할까요?예)select start_post_dt, end_post_dt, news_title (now() >= start_post_dt and now() <= end_post_dt) as DateInRangefrom dummy_table;
- 미해결실전! 스프링 데이터 JPA
MemberTest
MemberTest에서 changeTeam메소드를 테스트 해보고 싶어서 추가로 코딩해서 실행해보았습니다.근데 System.out.println(member1.getTeam().getName()); System.out.println(teamB.getMembers().stream().collect(Collectors.toList()));위의 코드에는 반영이 되는 데 h2에 select문으로 member를 쿼리해보면 반영이 안되어있더라구요. 제가 공부한바로는 em.flush(), em.close 하면 db에 반영되는 걸로 이해하고 있는데... 잘못이해하고 있는 건가요??
- 미해결실전! 스프링 데이터 JPA
영속성 컨텍스트와 데이터 베이스 동기화
안녕하세요 공부를 하던 중에 궁금한 점이 생겼습니다.제가 간단한 회원정보를 스프링 데이터 jpa로 저장을 했는데 그 후에 db에서 직접 값을 바꾸고 조회하니 당연히 영속성 컨텍스트에 있는 부분과 동기화가 안되어 원하는 값이 조회가 안됐습니다. 이런 경우에 바뀐 값을 조회하려면 memberservice 혹은 JpaRepostory를 상속받은 memberRepository에서 영속성 컨텍스트를 clear로 한 번 지워야 할 것 같은데 어떻게 해야 할지 잘 모르겠습니다.
- 미해결실전! 스프링 데이터 JPA
외래키가 없는 경우 조회
안녕하세요.강의를 통해서 많은 도움을 받고 있습니다.궁금한 내용은 외래키가 없는 경우의 데이터 조회입니다. 예를 들어서 <주문> 할 때에 <회원 정보>를 외래키로 넣으면 문제가 없는데...비회원 주문을 할 경우에는 <주문> 테이블에 들어갈 회원 컬럼에 null 값이 들어가게 됩니다.그러면 조회할 때 아주 조회가 안되는 문제가 있더라구요.실행되는 퀴리를 보면 inner join으로 나옵니다.예상에는 left join 하는 것처럼 빈 칸으로 나오리라 생각하는데 말이죠. 이럴 경우에는 어떻게 해야 할까요?어떻게 해야지 비회원 주문과 같이 외래키가 없는 경우에도 조회 할 수 있을까요?
- 미해결실전! 스프링 데이터 JPA
엔티티 매니저에 대해!!!!
[벌크성 수정 쿼리] 강의 11:20쯤에"같은 트랜잭션이면 같은 엔티티 매니저를 불러온다"라고 강사님이 언급을 하셨습니다.질문 : 엔티티 매니저는 싱글톤 객체처럼 딱 1개만 가지고 재활용하면서 사용하는 것이 아니라, 트랜잭션이 실행될 때[마다] 새로운 엔티티 매니저가 생성되는 건가요??
- 미해결실전! 스프링 데이터 JPA
member 테이블에 member!!!!!!!!!이 안나옵니다.
member 에 저장된 데이터가 없습빈다.
- 미해결실전! 스프링 데이터 JPA
메소드 이름으로 쿼리 생성 - 내부 동작
안녕하세요, [메소드 이름으로 쿼리 생성 메소드] 강의 중 메소드 이름을 분석해서 JPQL 쿼리 실행 부분에 질문이 있습니다. 예를 들어 findByUsernameAndEmail()과 같이 이름을 정의하였을 때, 내부적으로 SQL을 어떻게 생성하는지 궁금합니다. '자바 ORM 표준 JPA 기본편' 강의에서 em.persist()를 실행하면 영속성 컨텍스트 내부에서 SQL을 생성하고, SQL 쓰기 지연 저장소에 저장하는 것을 설명해주셨습니다. 즉, 컴파일 시점이 아닌, 런타임 시점 동적으로 쿼리를 생성하는 것으로 이해하였습니다. 위에서 말씀 드린 findByUsernameAndEmail()과 같은 경우 jpql로 변환되어서 쿼리가 실행된다고 말씀해주셨습니다. 어떠한 방법을 통해, 내부적으로 어떠한 로직을 거쳐 런타임에 jpql로 변환이 될 수 있는지 궁금합니다. 감사합니다.
- 해결됨실전! 스프링 데이터 JPA
편의성 메소드에 대한 질문입니다.
jpa 강의들을 보다보면entity 간에 양방향 연관관계를 설정한 경우위처럼 changeTeam 메소드를 추가 해주셨는데요.this.team = team; 의 경우 외래키(연관관계 주인) 이기 때문에 필요한 것은 이해를 했습니다. 그런데 team.getMembers().add(this); 부분의 경우기존에 member 테이블에 값들이 존재하고, 신규 회원이 새로운 트랜잭션에서 join 로직을 실행했을때, 해당 로직에서 생성된 team.members에는 기존의 member 값들은 add 되어있지 않은 상태일텐데, team.members를 제대로 사용이 가능한가 해서 질문드립니다. 제 생각에는 team.members를 정상적으로(?) 사용하려면 team과 member를 join 으로 가져 온뒤에 사용이 가능할 것 같습니다. list에 add 하는것만으로는 query가 발생하는게 아닌것으로 알고있습니다. 제가 이해를 잘 못 하고 있는 부분이 있는걸까요?아니면 단순히 편의성 메소드의 예시로 작성을 하시는건지 궁금합니다.