월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! 스프링 데이터 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가 발생하는게 아닌것으로 알고있습니다. 제가 이해를 잘 못 하고 있는 부분이 있는걸까요?아니면 단순히 편의성 메소드의 예시로 작성을 하시는건지 궁금합니다.
- 미해결실전! 스프링 데이터 JPA
@Param의 존재 이유>?
@EntityGraph(attributePaths = "team") List<Member> findEntityGraphByUsername(@Param("username")String username);이번 강의를 복습하다 보니까 강사님께서 @Param을 사용하셨더라구요.(강의 20:59)findByAge(), findOptionalByUsername()과 같은 메소드는 @Param 애노테이션 없이도 잘 동작 했는데 따로 특별한 이유가 있는 것일까요?
- 해결됨실전! 스프링 데이터 JPA
@GeneratedValue 질문하고싶어요
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 네2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)네3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]@GeneratedValue에서 지금은 autoincrement로숫자로 단순히 pk값이 1/2/3/4이런식으로 사용되고있는데MEMBER00001/MEMBER00002/MEMBER00003같이 PK값에 특정한 문자열이 앞에 들어가는경우는 어떻게하나요?
- 미해결실전! 스프링 데이터 JPA
지연로딩과 fetchJoin 성능 차이
즉시로딩을 사용하면 Member 객체를 불러 올 때 1+N문제가 발생하고 Lazy로딩을 사용하면 Team 객체를 사용할 때 쿼리문이 나가서 즉시로딩이든 지연로딩이든 결국 1+N 문제가 생기는 게 맞나요 ? 이 1+N 문제의 해결방법으로 fetchJoin이 나온 것 같은데 지연 로딩, 즉시 로딩보다 무조건 fetchJoin이 이점이 있는 것 아닌가요? 왜 디폴트값으로 지연로딩으로 설정하고 fetchJoin을 선택해서 사용하는지 궁금합니다. 기본적으로 fetchJoin을 사용하고 연관관계에 있는 객체를 사용하지 않을 것 같은 경우에만 지연로딩을 선택적으로 사용하는게 더 편하지 않나요? 사용하지 않는 객체를 가져오는 fetchJoin의 쿼리문 몇 줄이 성능에 그렇게 큰 영향을 미치나요?
- 미해결실전! 스프링 데이터 JPA
2분 정도에 이 코드는 안되는 이유가 있나요?
Team teamA = new Team("teamA"); Team teamB = new Team("teamB"); teamRepository.save(teamA); teamRepository.save(teamB); memberRepository.save(new Member("member1", 10, teamA)); memberRepository.save(new Member("member2", 10, teamB)); 강의에서 이렇게 한번에 하려다가 Member를 생성해주고 따로 save를 해주던데 한번에 하면 안되는 이유가 있을까요 ?
- 미해결실전! 스프링 데이터 JPA
Page 자료구조에 관해 질문입니다.
PageRequest pageRequest = PageRequest.of(0, 3, Sort.by(Direction.DESC, "username")); int age = 10; //when Page<Member> page = memberRepository.findByAge(age, pageRequest);PageRequest.of 코드에서 첫 번째 파라미터가 무엇을 의미하는지 헷갈립니다.PageRequest.of 의 2번째 파라미터는 한 페이지의 element 개수이고(limit), 3번째 파라미터는 정렬 조건이 맞나요?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(); page.getContent()는 현재 페이지의 데이터를 가져오는 메소드인가요?page.getNumber()는 현재 페이지를 가져오는 메소드인가요?Page는 책처럼 0,1,2,3 ... 이렇게 페이지가 있는 거고Content는 그 Page안에 있는 데이터를 의미하는 건가요? List<List<data>> 와 같은 구조로 되어 있는 것일까요? Page와 Content의 자료 구조가 어떻게 되어있는지가 궁금합니다.
- 미해결실전! 스프링 데이터 JPA
뭘 사용할지 선택에 있어서 질문입니다.
EntityManger를 주입받는 방법으로private final EntityManager em;이렇게 선언하고 @RequiredArgsConstructor로 받을 수도 있고, 이번 강의에서처럼 @PersistenceContext로 받을 수도 있는데 각각의 차이점이 무엇인가요 ? public long count() { return em.createQuery("select count(m) from Member m", Long.class) .getSingleResult(); }또 여기서 메소드 선언문에는 long 타입을 반환타입으로 설정했는데 createQuery의 2번째 파라미터로는 Long값을 주는데 어떤 이유인지 궁금합니다.
- 미해결실전! 스프링 데이터 JPA
@GeneratedValue에 관한 질문입니다.
member = Member(id=3, username=member1, age=10)-> member.getTeam() = Team(id=1, name=teamA)member = Member(id=4, username=member2, age=20)-> member.getTeam() = Team(id=1, name=teamA)member = Member(id=5, username=member3, age=30)-> member.getTeam() = Team(id=2, name=teamB)member = Member(id=6, username=member4, age=40)-> member.getTeam() = Team(id=2, name=teamB) Team을 먼저 persist 했기때문에 team의 id가 1,2가 됐고, 그 뒤에 순차적으로 member의 id가 3,4,5,6이 된 건가요 ? Team은 Team대로, Member는 Member대로 각 엔티티마다 id를 사용하는게 낫지 않나요? 실무에서는 어떤지 궁금하고, 만약 실무에서는 각 엔티티마다 id값을 공유한다면 강의에서는 모든 엔티티가 같은 id값을 공유하는지 궁금합니다.
- 미해결실전! 스프링 데이터 JPA
createQuery
public List<Member> findByPage(int age, int offset, int limit){ return em.createQuery("select m from Member m where m.age = :age order by m.username desc") .setParameter("age", age) .setFirstResult(offset) .setMaxResults(limit) .getResultList(); }em.createQuery("select m from Member m where m.age = :age order by m.username desc", Member.class)아래처럼 끝에 반환하는 클래스 타입을 적어줘야 된다고 기억을 하는데 위에 코드 처럼 적어주지 않아도 정상적으로 작동을 하더라구요? 반면에public long totalCount(int age){ return em.createQuery("select count(m) from Member m where m.age = :age") .setParameter("age", age) .getSingleResult(); }totalCount 의 경우 클래스 타입을 안적어주면 바로 빤갈줄이 그어지는데 반환하는 클래스 타입이 생략이 가능한 경우도 있는건가요??
- 해결됨실전! 스프링 데이터 JPA
질문은 아니지만 약간 바뀐 부분이 있는거 같아요.
강의자료 27페이지에 사진이랑 구조가 약간 바뀐거 같아요.현재 저는 스프링 3.0.6에 Java 17을 사용하고 있습니다.JpaRepository는 ListCrudRepository<T, ID>, ListPagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T>를 상속하고 있어요ListPagingAndSortingRepository는 결국 강의에서 말씀하신 PagingAndSortingRepository를 상속하네요.큰 틀에서 이해하는데는 문제없었습니다!좋은 강의 감사합니다.
- 해결됨실전! 스프링 데이터 JPA
마지막 bulkUpdate 테스트부분 질문입니다
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용] 질문1. 마지막 bulkUpdate 테스트는 통과되었으나 member5 코드 부분에서 sout 이찍히지 않습니다. 어떤 문제일까요 ?@Test public void bulkUpdate() { memberRepository.save(new Member("member1", 10)); memberRepository.save(new Member("member2", 19)); memberRepository.save(new Member("member3", 20)); memberRepository.save(new Member("member4", 21)); memberRepository.save(new Member("member5", 40)); int resultCount = memberRepository.bulkAgePlus(20); em.clear(); List<Member> result = memberRepository.findListByUsername("member5"); Member member5 = result.get(0); System.out.println("member5 = " + member5); Assertions.assertThat(resultCount).isEqualTo(3); } 질문2. 첫번째 코드보시면 아시겠지만 Member member5 = result.get(0);여기에서 get(0)은 인덱스를 의미하는건가요??아니면 db의첫번째 로우를 가져오겠다는 건가요??
- 미해결실전! 스프링 데이터 JPA
MemberRepositoryImpl 네이밍 관련 질문
강의에서 사용자 정의 리포지토리 인터페이스로 만들고, 이걸 구현한 클래스 이름은 리포지토리+Impl 이여야 된다고 하셨는데(강의에서는 MemberRepositoryImpl), 처음에 모르고 MemberRepositoryCustomImpl 로 구현 클래스 이름을 정했는데 테스트 코드도 잘 돌아가고 Query도 동일하게 나왔습니다 ...MemberRepositoryImpl 가 아니면 오류나야 되는 게 아닌가요 ? MemberRepositoryCustomImpl 로 했는데도 잘 작동한 이유가 궁금합니다 ... 네이밍이 틀려도 상관 없는건가요 ..?
- 해결됨실전! 스프링 데이터 JPA
username 카멜케이스 질문
[질문 내용]별건아니고 그냥 궁금해서 그런건데,username에선 카멜케이스를 적용하지 않으시고,teamName에선 카멜케이스를 적용하시는데 이게 관례상 username은 한단어로 취급하고 그런게 있는건가요?
- 해결됨실전! 스프링 데이터 JPA
스프링 데이터 jpa 페이징 (countQuery) 질문입니다
안녕하세요. 강의 영상보고 data jpa 를 사용해 프로젝트 진행중에 있습니다.다름이 아니라 카운트 쿼리에countQuery = "SELECT count(a) from Article a inner join fetch a.content where a.category =:categoryId and (a.title like %:keyword% or a.content.content like %:keyword%) join fetch 하면 에러가 발생하였고, 해다 에러 발생 이유는 구글링 후에 확인할 수 있었습니다.이유: 그런데 여기서 문제는 fetch join은 객체 그래프를 조회하는 기능이기 때문에 연관된 부모가 꼭 있어야 합니다. 그런데 수를 뽑는 count(u)로 조회 결과가 변경되어버렸기 때문에, 오류가 발생한 것이지요.그런데 하나 의문점이 생깁니다.해당 쿼리 내용을 보면, join 한 엔티티의 요소를 where절에서 찾고 있습니다.( a.content.content like %:keyword%)그런데 제가 알고 있는 개념으로는, 기본 Lazy loading 을 사용하게 되면, 연관되어 있는 엔티티를 프록시로 가져오는 것으로 알고 있습니다.그렇게 되면 저 where절의 부분에서 content가 프록시로 들어갔기 때문에, 올바르게 동작하면 안된다고 생각합니다.fetch를 사용하지 않아도, inner join으로만 쿼리가 날라가도, 쿼리 자체는 전부 실행되는 것인가요?그런데 가만히 생각해보면 그런 방식이라면, 지연로딩을 사용하는 방식이 사용자가 필요로 하지 않는 정보까지 join 하는 데이터베이스의 부하를 줄이기 위해 이렇게 하는 것으로 알고 있는데, fetch를 사용하지 않아도 데이터베이스에는 완전한 쿼리가 날라간다면, 이걸 굳이 스프링이 proxy로 끼워줄 필요가 있나? 하는 생각도 듭니다. 따라서 요약해보면,카운트 쿼리에서 조건에 따라 count 가 달라지므로, join을 할 때 fetch 를 넣지 않아도, 올바르게 작동하는 것이 맞는지맞다면 fetch를 사용하지 않아도 실제 데이터베이스에는 join 연산이 항상 일어나는 것이고, 대신 엔티티에 반환 해 줄 때, 프록시로 들어가는 것이고fetch 를 사용하게 되면 나왔던 모든 결과가 엔티티로 들어가 는 것이 맞는지 입니다.jpa 책이랑 웹 전부 뒤져봤는데 이 부분이 약간 모호해서 질문드립니다!
- 미해결실전! 스프링 데이터 JPA
스프링 데이터 JPA사용시 질문입니다.
[질문 내용]여기에 질문 내용을 남겨주세요.인터페이스로 repository을 만들고 JpaRepository상속할때 jpa활용1편 itemRepository처럼 save에 추가적으로 설정할때는 @Override 하고 기존 repositroy만드는거처럼 추가하면되나요?private final EntityManager em; public void save(Item item) { if (item.getId() == null) { em.persist(item); } else { em.merge(item); } }
- 미해결실전! 스프링 데이터 JPA
엔티티에 setter 메소드를 구현하지 않았을 때, PK 값의 저장 과정에 대해 질문드립니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 안녕하세요. 평소에 생각하지 못했던 부분인데, 강의를 들으면서 좀 궁금한 점이 생겨서 질문드립니다.. 만약 엔티티에 setter 메소드를 구현하지 않았다면,@GeneratedValue를 사용해서 데이터가 DB에 저장될 때 PK값이 생성되도록 했다면, 그 생성된 PK값이 영속성 컨텍스트에서 관리되는 엔티티 객체에 어떻게 저장되는 것인지 궁금합니다.
- 미해결실전! 스프링 데이터 JPA
클린 아키텍처에서 JPA
클린 아키텍처 (및 헥사고날) 설계 시 JPA 영속성 계층을 어디에 두어야하는지 궁금합니다.일반적으로 해당 아키텍처에선 영속성 계층을 도메인 계층에서 분리시켜야 한다고 주장하던데 (육각형 안 Entity는 POJO이며, JPA Entity는 바깥의 Adapter에 구현하고 Mapper로 변환하는 형식), 이렇게 되면 JPA가 제공하는 lazy loading이나dirty checking 등의 이점은 포기해야 되는것일까요?도메인 모델에 JPA 코드를 사용하자니 이러한 아키텍트 원칙에 위배되는거 같고, 그렇다고 이걸 분리해놓으면 따로 구현해야될게 많아지니 고민입니다..타협을 한다면 어느 방식으로 하는게 좋을까요? 애초에 이러한 아키텍트 방식과 JPA는 (지향점이 다르기에) 어울리지 않는 것일까요?
- 미해결실전! 스프링 데이터 JPA
Setter, Merge, InvalidDataAccessApiUsageException Error
안녕하세요. Setter를 사용하고 싶지 않아서 아예 Setter를 사용하지 않는 방향으로 코드를 작성중입니다.Member1의 이름을 Member 1에서 Updated Member로 바꾸기 위해서 setUsername 함수를 사용하지 않고, 처음에 Member1의 아이디를 그대로 받는 생성자를 만들어서 이름 빼고 모두 똑같이 맞춰주고 Save를 하면 될 줄 알고 코드를 이렇게 작성했는데InvalidDataAccessApiUsageException:detached entity passed to persist라는 에러를 얻게 됬습니다.newMember1이라는 객체에 따로 뭘 하지도 않았는데 Detached 상태라고 해서 조금 의아해서 찾아봤는데 이미 영속성 컨텍스트에 id가 1인 Member1이 있는 상태에서 갑자기 쌩뚱맞게 똑같은 Identifier를 가진 NewMember를 Persist하려고 하니 생긴 오류인걸 알게 됬습니다.그래서 Setter없이 하는 방법은 정말 없을까 하다가 해당 글을 발견하게 되었고, 아래 스샷과 같이 Comment를 참고 해서, 해당 Oracle Reference에서 Merge라는 Method를 알게되었고(조금 밑으로 스크롤을 내려야합니다.) 현재 영속성 컨텍스트에 매개변수로 받은 Entity의 상태를 Merge한다는 내용이 제가 원래 하려던 생각과 맞는것 같아생각과 비슷한 것 같아 사용해 보았습니다.이렇게 Merge를 사용한 테스트코드에서는 테스트가 통과되고, 실제 DB에도 Member1의 이름이 Updated Member로 변경이 되었습니다. (Update Query도 실제로 실행되는것을 확인할 수 있었습니다.)JPA가 변경 감지를 통해서 Update를 해준다는것과 그게 정석이라고 말씀해 주셨고, 그렇게 JPA의 변경 감지를 사용하는게 상태를 마치 값변수처럼 직접 변경하는것 보다 좋을 것 같습니다.하지만 change~ 함수나 아래와 같이 다른 Setter를 대신하겠다고 만든 여러 함수들에서 이름만 set이 안들어갔지 결국 그 함수의 내용은 Setter랑 다를바가 없는데 이게 Setter를 사용하는것과 무슨 차이가 있는지 잘 모르겠습니다. Lombok의 @Setter를 사용해서 단지 모든 프로퍼티에 대해서 Setter를 만들어주지않고 개발자가 직접 지정한 부분만 Setter를 만들어 줄 수 있다는 측면에서는 차이가 있는것 같습니다.또한 제가 이렇게 Merge를 사용해서 Update를 하는게 확실히 다른 개발자 분들이 잘 사용하지 않은 방법인것 같긴합니다. 혹시 이렇게 Merge를 사용하는것에 대해서 어떠한 의견을 가지고 계신지 궁금합니다!감사합니다 :D
- 미해결실전! 스프링 데이터 JPA
Production에서의 p6spy의 보안문제는 생기지 않을까요?
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]안녕하세요. Production에서 p6spy의 사용에 대한 질문 드립니다. 성능을 고려해봐야한다고 말씀해주셨는데, 그것에 더해 p6spy에 의해 출력된 데이터가 만약 상당히 민감한 정보(비밀번호, 개인정보)를 출력하게 된다면 보안상 이슈도 고려를 해야하지 않을까라는 생각이 듭니다! 혹시 이 부분에 대해서 어떤 의견을 가지고 계신지 여쭤보고 싶습니다! 감사합니다 :D