엔티티 매니저는 엔티티를 저장하고 , 수정하고, 삭제하고, 조회하는 등 엔티티와 관련된 모든일을 처리한다. 이런 엔티티 매니저를 만드는것을 엔티티 매니저 팩토리 (공장) 이라고 말한다.
이때 주의점은 엔티티 매니저 팩토리는 생성하는데 비용이 많이 드므로, 딱 한번만 생성하고 이를 서로 다른 스레드 간 공유한다.
( 여러 스레드가 동시에 사용해도 안전하다!)
하지만 엔티티 매니저는 여러 스레드가 동시에 들어오면 동시성 문제가 생기므로, 스레드간 공유는 절대 안 된다!!
영속성 콘테스트 (persist context)란 엔티티를 영구 저장하는 환경 이라고 할 수 있다.
엔티티의 생명주기는
1. 비영속
2. 영속
3. 준영속
4. 삭제
로 존재하는데, 해당 상태는 모두 엔티티 매니저를 사용하여 변경 가능하다!
(엔티티 매니저 안에 영속성 콘텍스트라는 공간이 있고, 여기에 해당 엔티티들을 저장한다고 생각하면 쉽다~)
1. 비영속
엔티티가 생성만 되고 아직 매니저를 통해 아무 기능을 시행하지 않은 상태를 말한다.
String id = "id";
Member member = new Member();
member.setId(id);
member.setUsername("지현");
member.setAge(20);
2. 영속
엔티티를 em.persist() 를 통해 영속 컨텍스트에 저장한 상황이다.
이때부터 해당 엔티티는 영속 컨텍스트가 관리한다.
em.persist(member);
* 이때 em은 이미 앞의 코드에서
EntityManager em = emf.createEntityManager(); //엔티티 매니저 생성
코드를 통해 생성한 엔티티 매니저다.
3. 준영속
준영속이란 영속 상태였던 엔티티를 더이상 영속 컨텍스트가 관리하지 않을 때를 말한다.
영속 -> 준영속으로 바꾸는 방법은 세개의 방법이 있는데 모두 준영속이 되는 방법이 다르다.
- em.detach()
- em.clear()
- em.close()
해당 방법에 대한것은 1차캐시, 쓰기 지연등을 설명하고 난 후 다시 설명한다.
아래에 설명했다!
(1) em.detach(Entity entity)
- 특정 엔티티만 준영속 상태로 전환한다.
ex)
em.detach(member);
member 엔티티만 detach한다.
이때 member 엔티티는 1차캐시에서 삭제(스냅샷 포함) 및 memebr 엔티티와 관련된 SQL문도 쓰기 지연 저장소에서 삭제된다.
(2) em.clear()
- 모든 엔티티를 준영속 상태로 전환한다.
ex)
em.clear();
1차캐시 및 sql 저장소에서 모든 정보를 초기화시킨다.
(3)em.close()
- 영속성 컨텍스트를 종료하는것이므로, 해당 영속성 컨텍스트가 관리하던 모든 영속상태의 엔티티를 준영속으로 만든다.
ex)
em.close();
*
em.clear() vs em.close()
em.clear() : 영속성 컨텍스트 초기화
em.close() : 영속성 컨텍스트 종료
4. 삭제
엔티티를 영속석 컨텍스트와 db에서 삭제함을 뜻한다.
em.remove(member);
영속성 컨텍스트로 엔티티를 관리하면
- 1차 캐시 사용
- 영속석 컨텍스트는 내부에 캐시를 가지고 있는데, 이를 1차 캐시라 한다.
key와 value로 엔티티를 저장한다.
그래서 em.find()메서드를 통해 엔티티를 조회할 때, 먼저 1차 캐시에서 조사한 후 만약 찾는 엔티티가 없으면 DB에서 조회하는것이다. (이후 해당 엔티티를 1차캐시에 저장한다.)
- 동일성 보장
- 동일성과 동등성
동일성 : 실제 인스턴스가 같음. 가리키는 주소값이 같음. ( == 연산자 사용)
동등성 : 단순히 인스턴스가 가지는 '값' 이 같음. ( equals() 사용)
ex)
String str1 = new String("a");
String str2 = new String("a");
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
이럴때 결과는 각각
false
true
로 나온다.
- 트랜잭션을 지원하는 쓰기 지연
-엔티티 매니저는 트랜잭션을 커밋하기 전까지 DB에 엔티티를 저장하지 않고, 1차 캐시에 저장 및 영속 컨텍스트 내부의 쓰기 지연 SQL 저장소에 해당 커밋의 SQL을 모아둔다.
transaction.commit() 이후
- em(엔티티매니저)는 영속성 컨텍스트를 flush(플러시)한다.
이때 쓰기 지연 SQL 저장소에 모아둔 SQL문을 db에 보내어, 영속성 컨텍스트의 내용을 DB와 동기화 한 후, 실제 db 트랜잭션을 커밋한다.
* flush(플러시) : 변경내용을 db에 동기화한다.
* 영속성 컨텍스트를 flush하는 방법은 아래 세가지이다.
- em.flush() 직접호출
- transaction.commit() 호출 시 자동 호출
- JPQL쿼리 실행시 자동 호출
--> 쓰기지연을 사용하여 한번에 SQL문을 전달해 성능을 더 높일 수 있다.
- 변경 감지
- JPA는 엔티티를 영속성 컨텍스트에 저장할 때, 그 태초의 상태를 복사한 엔티티도 같이 저장하는데 이를 '스냅샷' 이라고 한다.
만약 내가 엔티티를 변경하고 싶을때, 트랜잭션 커밋을 하면
1. 엔티티 매니저 내부에서 flush()가 호출된다.
2. 엔티티와 스냅샷을 비교하여 변경사항을 찾는다.
3. 쓰기 지연 저장소의 sql을 db에 보낸다.
4. db 트랜잭션을 커밋한다.
의 순서로 엔티티 변경이 이루어진다.
* 영속 상태의 엔티티에서만 변경감지가 이루어진다.
* 칼럼이 너무 많은 엔티티는 비교하는데 시간이 오래 걸리므로, @DynamicUpdate 를 사용하여 수정된 내용만 반영 가능하다.
- 지연로딩
-연관된 엔티티를 프록시로 조회한다. 프록시를 실제 사용할 때 초기화 하면서 db를 조회한다.
의 장점이 있다.
'study > backend' 카테고리의 다른 글
[TIL] 13 엔티티 매핑 (0) | 2023.06.26 |
---|---|
[TIL]12 ResponseEntity (0) | 2023.06.25 |
[TIL] 10 H2 db 설치하기 (0) | 2023.06.22 |
[TIL] 08 @ManyToOne, @OneToMany.. (0) | 2023.06.20 |
[TIL] 07 @RequestMapping, @Builder (0) | 2023.06.19 |