Spring Data JPA 영속성 컨텍스트

Y39·2023년 4월 1일
0

toBeProgrammer

목록 보기
71/88

영속성 컨텍스트

: 메모리 저장소, 엔티티 타입과 식별자를 키로 사용하는 캐시

  • Entity Manger로 DB와 영속성 컨텍스트 사이에서 데이터 관리

Q1. 왜 두 entity가 다를까?

  • 상황: 하나씩 테스트를 했을 때는 문제가 없었지만, 통합테스트를 통과하지 못했음

영속성 컨텍스트 관리 상태

  • 비영속(New)
    : 영속성 컨텍스트로 관리가 안 됨

  • 영속(Managed)
    : 영속성 컨텍스트에게 관리됨

    • DB와 동기화되고 트랜잭션 커밋시에 변경 사항이 지속
  • 삭제(removed)
    : 영속성 컨텍스트와의 연결이 끊기고,변경 사항 지속X

  • 준영속(Detached)
    : 예전에는 영속성 컨텍스트로 관리 되었지만 지금은 아님

    • 유효한 entity지만 트랜잭션이 커밋될때 변경사항 지속되지 않음

    save() 분기처리

    준영속 entity와 영속으로 바뀐 entity는 다르다.

    • 다시 영속이 될 때, id가 바뀌기 때문에 다른 entity로 인식

결론

  • savaAndCompare() 때에는 비영속성-> 영속성
    • id: null 이기 때문에 바로 DB에 저장이 됨
      • DB에 저장되고 id가 생김 (1)
    • DB에 저장된 entity와 PEPPER은 같음
  • find() 때에는 준영속성 -> 영속성
    • 앞의 테스트에서 저장되었기 때문에 id: 1
    • 준영속성 -> 영속성이 되면서 id가 변경
    • id가 달라졌기 때문에 PEPPER과 다른 entity로 인식함


Q2.삭제를 했는데 왜 조회가 되나?

  • 상황: 삭제 -> 조회를 했는데 테스트가 통과함.
  • 이상한 점: select 쿼리를 JPA가 날리지 않음

원인

  • 삭제는 했지만, 영속성 컨텍스트 안에 남아있기 때문에

추가

  • findById()를 통해서 entity를 가져와 달라고 하는 건 실패함
  • DB에 없기 때문에 가져올 수는 없음.


Q3. 삭제를 했는데 왜 삽입이 안 되나?

  • 실패 이유: unique에 위반되기 때문에 실행 불가

1차 캐시와 쓰기 지연

  • id가 없는 경우(New, 비영속성)
    • DB에 먼저 저장후 id를 넣어줌
    • 그후 1차 캐시에 저장

  • id가 있는 경우
    • 1차 캐시에 먼저 저장
    • 쓰기 지연 SQL 저장소
      • 쿼리를 영속성 컨텍스트에 저장
    • 한번에 flush()를 통해서 DB에 반영

delete All

  • 먼저 findAll을 통해서 entity를 가져옴
  • 그 후에 for문을 통해서 delete를 실행

flush() 실행 조건

  • 강제로 flush() 실행
  • JPQL 쿼리를 실행
  • 트랜잭션이 커밋

문제의 원인

  • delete 문이 아직 쓰기 지연 저장소에 있음
  • saveAll()의 entity들은 id가 없음
    • 그래서 바로 DB에 저장을 시키려고함
      즉, DB에 있는 entity를 다시 저장하는 꼴

해결법

  1. flush() 사용
    • 테스트에서만 사용 권장
  2. delete를 JPQL로 실행
  3. transact commit을 함


Q4. 수정을 했는데 왜 그대로지?

  • 상황: save()를 했는데도 값이 변경되지 않았음

스냅샷

  • 엔티티가 변경이 되었는지 비교를 위한 대조군으로 스냅샷 이용

언제나 JPQL은 flush를 날릴까?

  • 아니다.
  • JPQL이 특정 컬럼에 대한 것이라면, 그 컬럼에 대한 flush만 날림

결론

  • JPQL이 적용되지 않는 이유
    • age와 관련된 쿼리가 기존에 없어서 flush되는 것은 없음
    • 또한 JPQL이 실행된다고 하더라도 자동으로 JPQL의 변경 내용이 flush 되는 건 아님.

해결법

  • repository에 @Modifying(clearAutomatically = true) 사용

Q4. team이 왜 null인가?


  • 상황: 팀을 넣어준 상태인데 sort가 되지 않는 이유는?

fetch = FetchType.LAZY

  • Proxy 객체: 가짜 객체, 실제 entity를 꺼낼때 채우겠다는 의미

해결방법

  1. compare을 필드를 직접 가져오지 않고 getTitle로 가져옴
profile
System.out.print("Bold")

0개의 댓글