월 17,600원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결실전! 스프링 데이터 JPA
Member 엔티티의 연관관계 메서드에 대해 질문드립니다.
Member 엔티티의 연관관계 메서드(changeTeam)는 멤버가 기존에 속한 팀을 매개변수로 전달한 새로운 팀으로 변경합니다. 그런데 기존에 속한 팀의 리스트에서 멤버를 제거해주는 작업도 추가해줘야 하지 않나 싶은데, 예제기 때문에 단순화하기 위해 생락햐신건가요? private void changeTeam(Team team) { this.team = team; team.getMembers().add(this); // add()로 추가는 했지만, 기존의 팀에서 제거하는 코드는 없음 }
- 미해결실전! 스프링 데이터 JPA
스프링 부트 3.x버전은 쿼리가 다르게 나오나요?
slice 설명해주시는 부분인 16:30 부분에 쿼리가 저는 아래와 같이 나오는데 하이버네이트6 버전이여서 다르게 나오는 걸까요?selectm1_0.member_id,m1_0.age,m1_0.team_id,m1_0.usernamefrommember m1_0wherem1_0.age=?order bym1_0.username descoffset? rowsfetchfirst ? rows onlyList로 테스트 하는 경우도(18:57) 아래와 같이 다르게 나옵니다.selectm1_0.member_id,m1_0.age,m1_0.team_id,m1_0.usernamefrommember m1_0wherem1_0.age=?order bym1_0.username descoffset? rowsfetchfirst ? rows only
- 미해결실전! 스프링 데이터 JPA
JPA join 관련 질문
안녕하세요 JPA 학습중 join 관련하여 질문 드립니다. public class Score{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long scoreId; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") private Member member; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "game_id") private Game game; }Score라는 클래스가 있고, Game 엔티티와 ManyToOne 연관관계가 있을 때 public interface ScoreRepository extends JpaRepository<Score,Long>{ @Query("select s from Score s join s.game g left join s.member m left join m.profileImg p " + "where g.gameId=:gameId and (p.type = 'PROFILE' OR p IS NULL) order by s.totalScore desc") Slice<Score> findByGameId(@Param("gameId") Long gameId, Pageable pageable); } Game별 Score를 가져올 경우 해당 게임에 등록된 스코어가 없는 경우 결과가 반환되지 않아서 Game 엔티티의 게임명이나 게임타입 같은 게임정보를 가져올수가 없습니다. right join을 사용해보려 했는데 리턴값이 Slice<Score>라서 그런지 형변환 오류가 발생하는 것 같구요..이럴경우에는 Game 엔티티에서 @OneToMany 연관관계를 사용해서 결과를 가져와야하나요?? 그럴 경우 페이징은 어떻게 해결해야하는지 잘모르겠습니다..
- 미해결실전! 스프링 데이터 JPA
낙관적 락에 대해 질문이 있습니다.
Hibernate는 @Version을 사용하고, Lock 옵션을 @Lock(LockModeType.OPTIMISTIC)을 사용할 경우에 NONE 모드와 다르게 엔티티를 수정하지 않고 단순히 조회만 해도 버전을 확인한다고 강사님 JPA 책에 작성되어있습니다. 실제 코드로 구현해보니 버전만 확인하는거 같더라구요그 사이에 다른 트랜잭션이 해당 엔티티를 수정하여 버전이 변경되어도 ObjectOptimisticLockingFailureException 예외가 발생하지 않습니다. 간단하게 로직을 설명드리면 트랜잭션 A가 옵티미스틱 락 모드로 회원을 조회합니다. version = 0트랜잭션 A를 5초 대기합니다.트랜잭션 B가 회원을 수정하여 버전이 변경됩니다. version = 1트랜잭션 B가 종료됩니다.5초가 지나 트랜잭션 A가 종료됩니다.트랜잭션 A가 종료될 때 옵티미스틱 락 모드라서 마지막에 버전을 확인합니다.select version as version_ from member where id=?그런데 트랜잭션 A가 종료될때에 회원 버전이 다르지만 예외가 발생하지 않습니다. 이러면 OPTIMISTIC의 용도가 트랜잭션을 커밋할 때 버전 정보를 조회해서 현재 엔티티의 버전과 같은지 검증한다. 만약 같지 않으면 예외가 발생한다고 작성되어있는데 예외가 발생하지 않는다면 강사님께서 설명해주신 조회한 엔티티는 트랜잭션이 끝날 때까지 다른 트랜잭션에 의해 변경되지 않아야한다. 조회 시점부터 트랜잭션이 끝날때까지 조회한 엔티티가 변경되지 않음을 보장한다.이 말의 다른 의미가 어떤건지 궁금합니다 !아니면 제가 테스트를 잘못하고 있는 걸까요..? 아래는 로직에 대한 간단한 코드입니다.도메인package org.example.stock_rt_1.domain; import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; @Entity @Getter @NoArgsConstructor public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Long id; private long personId; private int age; @Version private Long version; public Member(long personId, int age) { this.personId = personId; this.age = age; } public void addAge() { ++this.age; } }리포지토리package org.example.stock_rt_1.repository; import jakarta.persistence.LockModeType; import org.example.stock_rt_1.domain.Member; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Lock; import java.util.Optional; public interface MemberRepository extends JpaRepository<Member, Long> { @Lock(LockModeType.OPTIMISTIC) Optional<Member> findByPersonId(Long id); }서비스package org.example.stock_rt_1.service; import lombok.RequiredArgsConstructor; import org.example.stock_rt_1.domain.Member; import org.example.stock_rt_1.repository.MemberRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Optional; @Service @RequiredArgsConstructor public class MemberService { public final MemberRepository memberRepository; @Transactional public void addAge(long personId) { sleep(500); //findMember가 먼저 실행되야하기 때문에 넣었습니다. Member member = memberRepository.findByPersonId(personId).orElseThrow(); member.addAge(); } @Transactional public void findMember(long personId) { memberRepository.findByPersonId(personId); sleep(5000); } private void sleep(long mills) { try { Thread.sleep(mills); } catch (InterruptedException e) { System.out.println("e = " + e.getMessage()); } } }테스트코드package org.example.stock_rt_1.service; import org.example.stock_rt_1.domain.Member; import org.example.stock_rt_1.repository.MemberRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class MemberServiceTest { @Autowired private MemberService memberService; @Autowired private MemberRepository memberRepository; @Test @DisplayName("회원 정보를 조회중 다른 트랜잭션에서 정보를 변경했다.") void addAge() throws InterruptedException { // given int personId = 5555; memberRepository.save(new Member(personId,15)); // when Thread selectThread = new Thread(() -> memberService.findMember(personId),"트랜잭션-A"); selectThread.start(); Thread updateThread = new Thread(() -> memberService.addAge(personId),"트랜잭션-B"); updateThread.start(); selectThread.join(); updateThread.join(); } }로그[트랜잭션-A] : select m1_0.id,m1_0.age,m1_0.person_id,m1_0.version from member m1_0 where m1_0.person_id=? Hibernate: select m1_0.id,m1_0.age,m1_0.person_id,m1_0.version from member m1_0 where m1_0.person_id=? [트랜잭션-B] : select m1_0.id,m1_0.age,m1_0.person_id,m1_0.version from member m1_0 where m1_0.person_id=? Hibernate: select m1_0.id,m1_0.age,m1_0.person_id,m1_0.version from member m1_0 where m1_0.person_id=? [트랜잭션-B] : update member set age=?,person_id=?,version=? where id=? and version=? [트랜잭션-B] : select version as version_ from member where id=? [트랜잭션-A] : select version as version_ from member where id=?
- 미해결실전! 스프링 데이터 JPA
PageRequest, pageable
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]이전 강의에서는 PageRequest.of(pagenum, pagesize, sort.by()) 를 사용해서 직접 설정해줘서 리포지토리 매서드에 인자로 넘겼는데 mvc의 @PageableDefault를 사용하면 이런 부분을 자동으로 처리해준다라고 이해해도 괜찮을까요?
- 미해결실전! 스프링 데이터 JPA
SpringDataJPA 의 page.getTotalElements 메서드의 공식 문서 링크는?
안녕하세요. Spring data jpa 페이징과 정렬 강의를 듣고있습니다. 아래 메서드를 사용하셨던데, 아래 메서드들에 대한 공식 문서를 찾고있는데 나오지가 않습니다.제가 공식 문서를 찾아보는데 익숙하지 않아 찾지 못한거같은데아래 메서드들에 대한 공식 문서가 있을까요?page.getTotalElements : 전체 Element 개수page.getNumber()page.getTotalPages()page.isFirst()page.hasNext
- 해결됨실전! 스프링 데이터 JPA
gavlyukovskiy 의존성을 추가했는데도 파라미터 로그가 보이지 않슴니다.
안녕하세요 다음과 같이 의존성을 했지만 보이지 않습니다. 무슨 문제가 있을까요?다음과 같이 로그가 뜨며 현재 psy 관련 로그는 보이지 않습니다. dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.7' }
- 미해결실전! 스프링 데이터 JPA
@SQLInsert 관련 질문입니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요?아니오2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)예[질문 내용]@Data @Entity(name="ha2_meta_usable_customlog_table") @Table(uniqueConstraints = { @UniqueConstraint(columnNames = {"category", "grouping"}) }) @SQLInsert(sql="REPLACE INTO ha2_meta_usable_customlog_table(category, grouping) VALUES(?,?)") public class Table{ @Id @GeneratedValue private long idx; @Column private String category; @Column private String grouping; } 코드가 위와 같은데 @SQLInsert 가 어떻게 적용되는건지 잘 모르겠어서 질문남깁니다...
- 미해결실전! 스프링 데이터 JPA
Jpa(Hibernate)가 올라오는 과정을 공부해 보고 싶습니다.
안녕하세요 Spring Data jpa 이용해서 프로젝트를 하던중 웹 검색을 하다가 아래와 같이 사용할 수 있다는 것을 알게 되었습니다.public interface ItemRepository<T extends Item> extends JpaRepository<T, Long> {} public interface BookRepository extends JpaRepository<Book, Long> {} public interface AlbumRepository extends JpaRepository<Album, Long> {} public interface MovieRepository extends JpaRepository<Movie, Long> {}Item을 상속받은 객체를 repository ItemRepository 에 넣으면 잘 들어갑니다.더 신기한 것은 Item객체를 상속 받은 Book객체를 BookRepository에서 찾을 수 있습니다. 아마 내부적으로 Jpa(hibernate)에서 엔티티에 있는 어노테이션을 뒤져서 조인 전략을 사용한 것이라는 사실을 애플리케이션 시작 전에 알고 있을텐데, 정확히 어떤 방식으로 이것을 귀신같이 알고 있는 건지 잘 이해가 되지 않습니다.(item객체인지만 알 수 있을텐데, 어떻게 BookRepsoitory에도 나머지 데이터를 넣어주는지 너무 궁금합니다.)DataJpa나 하이버네이트 관련 메뉴얼도 많이 찾아 보았는데, 내부적으로 작동하는 것에 대해서는 크게 설명하지 않고 사용법만 있어서 해당 부분 키워드나 방법이라도 알 수 있지 않을까 싶어서 질문 드립니다. 그리고 위의 예제는 아래 블로그에서 찾을 수 있었는데, 강의에 있던 내용이라고 댓글에 적혀 있었는데요제가 빼먹은 건가 싶어서 열심히 책과 모든 강의를 찾아보았지만.. 저는 찾을 수 없었는데요, 혹시라도 강의에서 언급 하시고 넘어가셨다면 해당 부분이라도 알고 싶습니다.블로그 링크는 아래와 같습니다.https://jyami.tistory.com/23 감사합니다.
- 미해결실전! 스프링 데이터 JPA
@Modifying 에서 무조건 테스트 데이터가 커밋되고 있습니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요, 영한님.좋은 강의 늘 감사합니다. 최근에 제가 공부한 내용들을 정리하면서 포트폴리오를 만들고 있는데, 특이하게도 @Modifying 을 사용하는 코드를 테스트할 때만 해당 테스트의 데이터가 롤백 되지 않고 커밋되는 기이한 현상을 발견했는데, 혹시 아시는 바가 있으신가 해서 여쭤봅니다. @Modifying 을 사용하는 코드'만' 테스트할 때는 테스트 통과하고 데이터가 롤백됩니다.당연한 이야기지만, @Modifying 코드를 제외한 테스트가 통과하고 롤백됩니다.하지만 이들을 동시에 실행하면 @Modifying 에서 update 된 데이터들이 롤백되지 않고 남아 있어서 다른 데이터에 영향을 주게 됩니다. 회사에서도 벌크성 수정 쿼리를 이미 사용을 하고 있고, 그 코드들을 테스트함에 있어서 어떠한 이슈도 발생하지 않았는데 제 포트폴리오에서만 이런 이슈가 발생을 하네요... 트랜잭션 전파와 관련된 문제, h2 와 boot 버전(3.2.1.) 문제 등등 의심 되는 부분들 여러 가지로 고쳐보고 바꿔봐도 여전합니다. boot 도 3.0.x 대로 낮춰보기도 했고. stackoverflow, spring boot github 등에도 찾아봤습니다만 저와 같은 이슈를 겪는 사람은 보지 못 했습니다. 그렇다고 해서 테스트 때문에 제품 코드를 바꾸는 건 또 주객전도가 되니 테스트에 tearDown 으로 데이터를 날리려고 합니다. 그래도 발생한 이슈에 대해 정리하고 해결은 해야 하니 여전히 알아보고 있는 중입니다. 그중에 혹시 영한 님께서는 알고 계시는 바가 있으신가 해서 여쭤봅니다. 제 소스코드 repository 와 이슈가 발생하는 코드들을 남깁니다. 참고로 제 컴퓨터에서 테스트를 실패하는 상태 그대로를 올립니다. 혹시 필요하신 정보가 더 있으시면 말씀해주세요.감사합니다. 테스트 로그 https://drive.google.com/file/d/117sWM8NZa13wIWUc-XhCpYFdZ9oeIUK4/view?usp=sharing테스트의 로그 전부를 넣었습니다. 위에서 설명해드린 것처럼 @Modifying 테스트 이후 그 데이터가 남아서 다른 테스트들에 영향을 주는 것이기 때문에 실패하는 테스트는 매번 다릅니다.github https://github.com/psam1017/sunder-backend/tree/feat/teachermain 은 테스트를 통과하도록 변경감지를 사용한 상태이고, 위처럼 feat/teacher 브랜치에 실패하는 코드를 올렸습니다. @Modifying 사용 코드 - repository https://github.com/psam1017/sunder-backend/blob/feat/teacher/src/main/java/psam/portfolio/sunder/english/domain/academy/repository/AcademyCommandRepository.java@Modifying 사용 코드 - service https://github.com/psam1017/sunder-backend/blob/feat/teacher/src/main/java/psam/portfolio/sunder/english/domain/academy/service/AcademyCommandService.java#L245@Modifying 을 테스트하는 코드 https://github.com/psam1017/sunder-backend/blob/feat/teacher/src/test/java/psam/portfolio/sunder/english/scheduler/AcademySchedulerTest.java테스트 코드 설정 관련 코드 https://github.com/psam1017/sunder-backend/blob/feat/teacher/src/test/java/psam/portfolio/sunder/english/SunderApplicationTests.java
- 미해결실전! 스프링 데이터 JPA
JpaMetamodelEntityInformation 내부의 isNew 메서드에서 조건 분기 시 다음 조건은 무엇을 의미하나요?
public boolean isNew(T entity) { if (!this.versionAttribute.isEmpty() && !(Boolean)this.versionAttribute.map(Attribute::getJavaType).map(Class::isPrimitive).orElse(false)) { BeanWrapper wrapper = new DirectFieldAccessFallbackBeanWrapper(entity); return (Boolean)this.versionAttribute.map((it) -> { return wrapper.getPropertyValue(it.getName()) == null; }).orElse(true); } else { return super.isNew(entity); } } 조건문을 타지 않고 else 절로 넘어가면 super.isNew()를 호출하고, 상위 추상 클래스인 AbstractEntityInformation 클래스의 isNew() 메서드에서 Entity id 필드가 Null, 0L인지 판단하는 걸로 이해했습니다.강의 범위가 아니긴 하지만 JpaMetamodelEntityInformation 클래스의 isNew() 내에서 versionAttribute가 존재하는지 확인하는 부분은 어떤 것을 확인하는 것인지 궁금합니다.
- 미해결실전! 스프링 데이터 JPA
Merge 관련해서 질문드립니다.
안녕하세요 영한님, 정말 좋은강의 잘 듣고있습니다. Merge관련해서 질문이 하나있는데요..! 아래 두 method 모두 시작할때 persistence context가 비어있고 찾는 entity가 db에 있다고 가정할때 비슷한 (혹은 같은) flow로 진행될까요? 여기서 method parameter, Entity e,는 업데이트될 (id가 set되어있고 field가 업데이트 되어있는)객체입니다. @Transactional public void updateEntity(Entity e){ Entity foundEntity = em.find(Entity.class, e.getid()); foundEntity.setFieldOne("New Data"); }@Transactional public void updateEntity(Entity e){ em.merge(e); }Merge를 꼭 써야하는건 아니지만, 그냥 동작 메커니즘이 궁금해서 질문드립니다. Merge를 쓰는게 Update전에 항상 Select query로 db에서 객체를 조회하기때문에 쓰기를 지양하라고 하시는건가요, 아니면 merge를 쓸때 또 다른 downside가 있나요?
- 해결됨실전! 스프링 데이터 JPA
findById 동시성 테스트 실패
MemberRepository는 jpaRepository인 상태이고,findById관련해서 동시성 테스트를 하고 있는데, 해당 테스트가 통과를 하지 않아 그 이유가 궁금합니다. 단순하게 여러 스레드에서 findById하는 테스트 코드인데 왜 통과를 못하는지 잘 이해가 가지 않습니다. @SpringBootTest @Transactional public class Test{ @Autowired MemberRepository memberRepository; Member member; @BeforeEach void setUp() { member = Member.builder().name("testMember").build(); memberRepository.save(member); } @Test public void test() throws Exception { int threadCount = 10; ExecutorService executorService = Executors.newFixedThreadPool(threadCount); CountDownLatch latch = new CountDownLatch(threadCount); AtomicInteger failCount = new AtomicInteger(); AtomicInteger successCount = new AtomicInteger(); for (int i = 0; i < threadCount; i++) { executorService.submit( () -> { try { memberRepository.findById(member.getId()).get(); successCount.addAndGet(1); } catch (Exception e) { System.out.println(e.getMessage()); failCount.addAndGet(1); }finally { latch.countDown(); } } ); } latch.await(); assertThat(successCount.get()).isEqualTo(threadCount); assertThat(failCount.get()).isEqualTo(0); } }
- 미해결실전! 스프링 데이터 JPA
쿼리 메서드 @Query시 limit
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요, 강의 듣는 도중 궁금증이 생겨 질문드립니다.만약 쿼리 메서드를 사용하여 특정 조건에 의해 게시물 10개만 가져오고 싶을 때List<Board> findTop10ByWriteDatetimeGreaterThanOrderByCommentCountDescViewCountDescWriteDatetimeDesc(String writeDatetime);과 같이 지저분하게 코드를 작성할 수 있었는데 메서드 이름이 너무 길어져 @Query를 사용해서 코드 양을 줄이고 싶었습니다. 하지만, jpql에 limit를 사용할 수 없는데 이 경우 어떻게 jpql을 작성해야 하는지 궁금합니다.
- 미해결실전! 스프링 데이터 JPA
강의 수강 중 질문이 있습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 강의 내용을 듣고 제가 따로 프로젝트를 만들어서 비교를 해 보았는데@Entity @DynamicInsert @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class User { @Id private String id; // 이메일 형식 @Column(nullable = false) private String password; @Column(nullable = false) private String name; @Column(nullable = false, unique = true) private String nickname; @Column(nullable = false, unique = true) private String phone; @CreationTimestamp @Column(nullable = false) private LocalDateTime createAt; @Enumerated(EnumType.STRING) @ColumnDefault("'NORMAL'") private UserStatus status; // 이미지 변수 (프로필 사진) public User(String id, String password, String name, String nickname, String phone) { this.id = id; this.password = password; this.name = name; this.nickname = nickname; this.phone = phone; } }@Test public void basicCRUD() { User user1 = new User("user1","123","kk","sssss","123213213"); User user2 = new User("user2","1321","dd","dddd","21312412412421"); userRepository.save(user1); userRepository.save(user2); //단건 조회 검증 User findUser1 = userRepository.findById(user1.getId()).get(); User findUser2 = userRepository.findById(user2.getId()).get(); assertThat(findUser1).isEqualTo(user1); assertThat(findUser2).isEqualTo(user2);테스트를 실행 시켜보니Expected :com.clickpick.domain.User@51577fc8Actual :com.clickpick.domain.User@4dbeae45 오류가 발생하였습니다.강사님의 강의를 따라했을 땐 동일하다고 하였는데 저의 예시로 해보니 동일하지 않다고 나오는데 어느부분에서 차이점이 생긴지 알고싶습니다 참고로 repository는public interface UserRepository extends JpaRepository<User, String> { } 입니다.
- 해결됨실전! 스프링 데이터 JPA
페치조인과 new 프로젝션
Member Entity@Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Builder @AllArgsConstructor @ToString(of = {"id", "username", "age"}) @NamedQuery( name = "Member.findByAgeGreaterThanAndUsername", query = "select m from Member m where m.age > :age and m.username = :username" ) public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "member_id") private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "team_id") private Team team; private String username; private int age; /** * 연관관계 편의 메서드 */ public void changeTeam(Team team) { this.team = team; team.getMembers().add(this); } } Team Entity@Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Builder @AllArgsConstructor @ToString(of = {"id", "name"}) public class Team { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "team_id") private Long id; @OneToMany(mappedBy = "team", fetch = FetchType.LAZY) @Builder.Default private List<Member> members = new ArrayList<>(); private String name; } MemberRepositorypublic interface MemberSpringJpaRepository extends JpaRepository<Member, Long> { List<Member> findByUsernameAndAgeGreaterThan(String username, int age); @Query(name = "Member.findByAgeGreaterThanAndUsername") List<Member> findByAgeGreaterThanAndUsername(@Param("age") int age, @Param("username") String username); @Query(value = "select m from Member m") List<Member> findUsers(); @Query(value = "select new study.datajpa.dto.MemberDto(m.id, m.username, t.name) from Member m join m.team t") List<MemberDto> findMemberDtoWithJoin(); /** * fetch join -> new 프로젝션 예외 터짐 */ // @Query(value = "select new study.datajpa.dto.MemberDto(m.id, m.username, t.name) from Member m join fetch m.team t") // List<MemberDto> findMemberDtoWithFetchJoin(); @Query(value = "select m from Member m join m.team t") List<Member> findMemberJoinWithTeam(); } 질문 /** * join -> new 프로젝션 정상 수행 */ @Query(value = "select new study.datajpa.dto.MemberDto(m.id, m.username, t.name) from Member m join m.team t") List<MemberDto> findMemberDtoWithJoin(); /** * fetch join -> new 프로젝션 예외 터짐 */ // @Query(value = "select new study.datajpa.dto.MemberDto(m.id, m.username, t.name) from Member m join fetch m.team t") // List<MemberDto> findMemberDtoWithFetchJoin();@Query 애너테이션에서 쿼리문을 작성할 때, new 연산자를 사용하여 dto로 변환하여 반환하려고 합니다. Member-Team을 join 후 new 연산자를 사용하여 dto는 정상적으로 반환이 됩니다. 근데 페치조인을 사용 후 new 연산자를 사용하면 아래 예외가 터집니다.fetch join으로는 new 연산자 사용이 안 되는 이유를 알고싶습니다. 발생하는 예외java.lang.IllegalStateException: Failed to load ApplicationContext for [WebMergedContextConfiguration@3d1b6816 testClass = study.datajpa.repository.springjpa.MemberSpringJpaRepositoryTest, locations = [], classes = [study.datajpa.DataJpaApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@1255b1d1, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@47da3952, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@28a0fd6c, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@5fb97279, org.springframework.boot.test.context.SpringBootTestAnnotation@3f26d230], resourceBasePath = "src/main/webapp", contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null]
- 해결됨실전! 스프링 데이터 JPA
파라미터로 받은 form을 어떻게 엔터티로 반환하는지 모르겠어요...
현재 실전 데이터 JPA수강 중인데요.. 독학 중이라 토이프로젝트로 연습하는데 오늘까지 배운 JpaRepository 상속과 관련하여 회원가입 기능 구현하려 하려는데 어디 물어볼곳이 없고 뒤죽박죽이라 정리가 필요해서 장문의 질문을 남깁니다.. 일단 제가 머릿속에 정리가 안되는 것은 영한선생님께서 최대한 컨트롤러에 엔터티를 노출하지 말고 비지니스 로직을 서비스에서 최대한 구현하라고 해서 따라하는 중인데 Member를 기준으로 파라미터를 받을 MemberForm을 생성했습니다. 여기서 질문이.. MemberForm을 생성했으면 MemberDto는 따로 생성 안해도 될까요?컨트롤러를 그림과 같이 작성하였고서비스는 아래와같이 하였는데... 뭔가 서비스에서 엔터티를 직접 만지니까 찝찝한데 실무에서도 이렇게 하는지 궁금합니다..
- 해결됨실전! 스프링 데이터 JPA
AttributeConverter에 대해 질문이 있습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 네2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 네3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 네[질문 내용]안녕하세요 AttributeConverter 관련 질문이 있습니다. attribute와 dbDate를 암호화 & 복호화하는 사용자 정의 컨버터를 구현했는데 실제 query를 이용하여 조회했을 때 정상적으로 암호화된 데이터가 적재된 것을 확인했습니다.다만 애플리케이션에서는 converter가 동작하니 실제로 암호화 된 데이터가 적재되었는지를 애플리케이션 레벨에서 할 수 없는데 이를 위한 테스트 작성을 어떻게 해야하는지 궁금합니다.
- 해결됨실전! 스프링 데이터 JPA
UserForm(실전 1편에서 사용한)도 DTO 조회 쿼리문처럼 사용하면 될까요?
실전 1편에서 영한샘 회원 가입이나 주문 Order를 Form을 사용하셧는데요.... 단순한 save를 쓰더라도 UserForm을 사용시에는 DTO 조회 쿼리 작성 예시처럼 인터페이스 MemberRepository에 저렇게 사용해야하는지 궁금합니다
- 해결됨실전! 스프링 데이터 JPA
Repository를 구현하는 클래스는 JpaRepository 기능 구현 안해도 되나요?
제가 인터페이스 편 공부할 떄...예를들어 A인터페이스와 B인터페이스가 있고A가 B를 상속하고 클래스인 C가 A를 implement하게 되면 C는 부모인 A인터페이스의 기능은 물론이고 A가 상속 중인 B의 기능까지도 다 구현해야한다고 배웠는데.. 그냥 JpaRepository는 특별한 놈이라 그럴 필요 없다라고 암기하면 될까요?..