문제상황 1.
save, find 테스트 메서드가 각각은 잘 동작을 한다 →근데 같이 쓰니까 문제 발생
자세히 보니 동시성 보장 자체가 안되고 있음
엔티티 생명주기
-
비영속(new)
- 영속성 컨텍스트와 전혀 관계가 없이 객체가 생성만된 상태
-
준영속(detatched)
- 영속성 컨텍스트에 저장되었다 분리되어 현재 관리하고 있지 않은 상태
- 영속 → 준영속 예시
- detatch : 특정 엔티티만 준영속 상태로 전환
- clear : 영속성 컨텍스트를 완전히 초기화
- clear는 1차 캐시에 상관없이 쿼리를 확인하고 싶을 때 즉, testcase 작성 시에 도움이 된다.
- close : 영속성 컨텍스트를 종료
-
영속(managed)
- 영속성 컨텍스트에 저장된 상태
- 영속성 컨텍스트는 엔티티를 식별자로 구분함으로, 영속상태의 엔티티는 반드시 식별자(id)가 있다!
- 영속 상태가 되었다고 바로 DB 쿼리가 날라가지 않고 transaction commit 시점에 DB 쿼리 날라감
- 예시
- em.persist()로 영속성 컨텍스트에 저장된 상태
- em.find()로 조회할 때, 1차 캐시에 없어서 DB에서 조회한 후 해당 엔티티를 1차 캐시에 올라간 상태
-
삭제(removed)
- ID값이 있고 영속성 컨텍스트와 연결되어있고 DB 삭제 상테를 예약해둔 상태
- 실제로 DB에서 바로 삭제된 것은 아니다
- 따라서 delete한 엔티티 조회가 가능하다. isPresent로 값을 확인하면 없다고 나옴 → 값을 빼올 수는 없음
-
해결방안
- 항상 save 메서드에서 리턴된 영속성이 보장된 엔티티를 사용하라
- 어자피 영속성 컨텍스트에서 조회하기때문에 쿼리문을 사용하는 것이 아님!
- 동일성 보장을 위해서 이렇게 사용하는 것을 추천
문제상황2
: 객체들 save → deleteAll → 동일한 형태의 객체들 saveAll (DataIntegrityViolationError) → 왜?
Flush 타이밍?
- 강제 flush
- JPQL 쿼리 실행될 때
- 트랜잭션 커밋 시에