/*
* [참고]
* 개체 Entity : 정보를 표현하는 단위, 의미있는 하나의 정보 단위
* 객체 Object : 의미있는 속성들이 모인것
* 클래스 Class : 객체를 만들기 위한 설계도, 연관되어있는 변수와 메소드의 집합
* 인스턴스 Instance : 설계도를 바탕으로 소프트웨어에 구현된 실체, 메모리에 올라가있는 객체
*
* 동일성 indentity : 실제 인스턴스가 같다. ==
* 동등성 equality : 실제 인스턴스는 다르지만, 인스턴스가 가지고 있는 값이 같다. equals()
*
* 스냅샷 snapshot : 엔티티를 영속성 컨텍스트에 보관할 때, 최초 상태를 복사해서 저장해두는 것
*/
[영속성 컨텍스트란?]
1. 엔티티를 영구 저장하는 환경 이라는 뜻
2. 엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 영속성 컨텍스트에 엔티티를 보관하고 관리한다.
3. manager.persist(user);
persist() 매소드를 정확히 얘기하면 엔티티 매니저를 사용해서 회원 엔티티를 영속성 컨텍스트에 저장하는 매소드다.
[엔티티의 생명주기]
1. 비영속 : 영속성 컨텍스트와 전혀 관계가 없는 상태
▶엔티티 객체를 생성하고 아직 저장을 안했을때, 순수한 객체상태를 의미
2. 영속 : 영속성 컨텍스트에 저장된 상태
▶ 저장, 조회 등 행위를 행하였을때, 영속성 컨텍스트가 관리하는 상태를 의미
3. 준영속 : 영속성 컨텍스트에 저장되었다가 분리된 상태
▶manager.detach(), manager.close(), manager.clear()
영속성 컨텍스트 초기화하여 영속성 컨텍스트가 관리를 하지않는 상태
4. 삭제 : 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제한다.
▶manager.remove(user)
[영속성 컨텍스트가 엔티티를 관리했을때의 장점]
1. 1차 캐시
▶manager.persist(user)를 실행하면 1차 캐시에 회원 엔티티를 저장.
회원 엔티티는 아직 DB에 저장되지 않은 상태.
▶manager.find(User.class, "홍길동")을 실행하면 1차 캐시에서 먼저 조회 후
1차 캐시에 없다면 DB를 조회해서 엔티티 생성, 그리고 1차 캐시에 저장한 후에 영속상태의 엔티티를 반환.
2. 동일성 보장
▶ User one = manager.find(User.class, "홍길동")
User two = manager.find(User.class, "홍길동")
find 메소드를 반복해서 호출을 해도 영속성 컨텍스트는 1차 캐시에있는 같은 엔티티 인스턴스를 반환.
따라서 one == two 는 true
3. 트랜잭션을 지원하는 쓰기 지연
▶ 엔티티 매니저는 트랜잭션을 커밋하기 직전까지 DB에 엔티티를 저장하지 않고,
내부 쿼리 저장소에 쿼리를 모아두고, 트랜잭션을 커밋할 때 모아둔 쿼리를 DB에 보낸다.
이것을 '트랜잭션을 지원하는 쓰기 지연' 이라 함
▶ 쿼리를 그때그때 DB에 전달하더라도 트랜잭션을 커밋하지 않으면 아무 소용이 없다.
트랜잭션 커밋 직전에만 전달하면 되는데,
이렇게 모아서 한번에 전달하게되면 성능을 최적화할 수 있다.
4. 변경 감지 dirty checking
▶ 영속 상태의 엔티티의 변경사항을 DB에 자동으로 반영하는 기능
▶ 처리과정
1. 트랜잭션을 커밋하면 엔티티 매니저 내부에서 먼저 플러시(flush()) 호출
2. 엔티티와 스냅샷을 비교하여 변경된 엔티티 감지
3. 변경된 엔티티가 있으면 수정 쿼리를 생성해서 쓰기지연 SQL 저장소에 전송
4. 쓰기 지연 저장소의 SQL을 DB에 전송
5. DB 트랜잭션 커밋
5. 지연 로딩
▶ 실제 객체 대신 프록시 객체를 로딩해두고 해당 객체를 실제 사용할 때
영속성 컨텍스트를 통해 데이터를 불러오는 방법
[엔티티 수정]
▶ 따로 update() 메소드 없이, 변경 감지 기능으로 처리
▶ 엔티티의 모든 필드를 수정에 반영하여, 데이터 전송량이 증가하는 단점이 있다.
▶ 필드가 많거나 저장되는 내용이 크면 수정된 데이터만 동적으로 UPDATE SQL을
생성하는 전략을 사용해야 한다. → 하이버네이트의 확장 기능 사용
@org.hibernate.annotations.DynamicUpdate
@org.hibernate.annotations.DynamicInsert
기본 전략을 사용하다, 최적화가 필요할 정도로 느려지면 그때 전략을 수정하는 것을 추천한다 한다.
[엔티티 삭제]
▶ 엔티티를 삭제하려면 먼저 삭제 대상을 조회 후, manager.remove() 호출
엔티티 등록과 비슷하게 삭제 쿼리를 쓰기 지연 SQL 저장소에 등록
▶ 삭제 메소드를 호출하는 순간 해당 엔티티는 영속성 컨텍스트에서 제거된다.
이렇게 제거된 엔티티는 재사용하지 말고 가비지 컬렉션의 대상이 되도록 두는것이 좋다.
[플러시] flush()
▶ 영속성 컨텍스트에 보관된 엔티티는 유지된다.
영속성 컨텍스트의 변경 내용을 DB에 동기화하는 것 뿐이다.
▶ 영속성 컨텍스트를 플러시하는 방법
1. 직접 호출
-manager.flush() 메소드를 직접 호출
-테스트나 다른 프레임워크와 함께 사용할 때를 제외하고 거의 사용하지 않는다.
2. 특랜잭션 커밋 시 플러시 자동 호출
3. JPQL 쿼리 실행 시 플러시 자동 호출
-JPQL은 SQL로 변환되어 DB에서 엔티티를 조회한다.
하지만 그전 작업들이 플러시 되지 않았다면, DB에 없으므로 쿼리 결과로 조회되지 않는다.
이런 문제를 예방하기 위해 JPQL을 실행할 때, 플러시를 자동 호출한다.
[준영속]
▶ 영속성 컨텍스트가 관리하는 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된것
▶ 영속성 컨텍스트가 제공하는 기능을 사용할 수 없다.
▶ 준영속 상태로 만드는 방법
1. manager.detach(entitiy) : 특정 엔티티만 준영속 상태로 전환
2. manager.clear() : 영속성 컨텍스트를 완전히 초기화
3. manager.close() : 영속성 컨텍스트 종료
▶ 지연 로딩을 할 수 없다.
[병합] merge()
▶ 준영속 상태의 엔티티를 다시 영속 상태로 변경하는 방법
▶ 비영속 상태의 엔티티도 영속 상태로 만들 수 있다.
▶ manager.detach(user);
user.setUsername("준영속수정");
User mergedUser = manager.merge(user);
transaction.commit();
을 순서대로 실행하게 되면, 해당 회원의 이름은 변경된다.
▶ 정확히는, user 엔티티는 그대로 준영속 상태이고, mergedUser 엔티티가 새로운 영속 상태로
user의 자리를 이어가는 것이다.
'Jpa' 카테고리의 다른 글
번외. QueryDSL & JPA (0) | 2023.01.19 |
---|---|
5. 연관관계 매핑 (0) | 2023.01.19 |
4. 엔티티 매핑 (0) | 2023.01.19 |
2. JPA 설정 및 객체 매핑, 기본 어플리케이션 세팅 (0) | 2023.01.19 |
1. JPA 란? (0) | 2023.01.19 |