영속성 컨텍스트
- 엔티티를 영구 저장하는 환경이라는 뜻이다.
- EntityManager.persist(entity);
엔티티 매니저를 통해 영속성 컨텍스트에 접근할 수 있다.
엔티티의 생명주기
비영속 (new / transient)
- 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태를 말한다.
영속 (managed)
- 영속성 컨텍스트에 관리되는 상태이다. (1차캐시)
- EntityManager.persist(객체);
준영속 (detached)
- 영속성 컨텍스트에 저장되었다가 분리된 상태이다. 영속성 컨텍스트가 제공하는 기능을 사용하지 못한다.
- EntityManager.detach(객체);
- EntityManager.clear() // 영속성 컨텍스트를 완전히 초기화
- EntityManager.close() // 영속성 컨텍스트를 종료
삭제 (removed)
- 삭제된 상태이다.
- EntityManager.remove(객체);
영속성 컨텍스트의 이점
- 1차 캐시
- 동일성 보장
- 트랜잭션을 지원하는 쓰기 지연
- 변경 감지
- 지연로딩
1차캐시에 대해서
엔티티가 영속상태가 되면 1차 캐시에 저장이 된다.
1차 캐시에 저장된 엔티티를 조회하면, 1차 캐시에 먼저 해당 엔티티가 있는지 확인 후, 있다면 1차 캐시에서 가져오고
없다면 DB 에서 조회를 해온 후 1차 캐시에 저장하여 반환하는 구조를 가지고 있다.
따라서
Member member1 = em.find(Member.class, "홍길동");
Member member2 = em.find(Member.class, "홍길동"); 이 두 가지 member를 비교한다면
member1 == member2 상태가 되어 영속 엔티티의 동일성을 보장해준다.
엔티티 등록
엔티티 매니저는 데이터를 변경할 때 반드시 트랜잭션을 시작해야한다.
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); //db와 연결도 다 됨.
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin(); //트랜잭션 시작
//code
try {
Member memberA = new Member();
memberA.setId(1L);
memberA.setUsername("김솔라");
em.persist(memberA); //이때 db에 sql을 보내지 않음. sql을 쓰기지연sql저장소에 쌓아둔다고 생각.
tx.commit(); //트랜잭션 커밋하는 순간 데이터베이스에 sql을 보낸다.
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
해당 코드를 실행하면, DB에 Id:1, name:김솔라 로 잘 들어와져있다.
sql은 persist()에서가 아닌 commit을 할때 쿼리가 보내진다.
엔티티 수정(변경 감지)
tx.begin();
//code
try {
Member memberA = em.find(Member.class, 1L);
//엔티티 데이터 수정
memberA.setUsername("김아지");
tx.commit();
이 코드만 실행하면 해당 memberA의 이름이 "김아지"로 변경된다.
어떻게 em.update(memberA)와 같은 코드를 써서 해당 데이터가 변경되었다고 알려주는 것 없이 DB는 변경을 할 수 있는 걸까?
member를 find()으로 받아오면서, memberA는 1차 캐시에 담겨져있다. 이때 스냅샷이라는 것도 같이 저장되어있는데,
엔티티가 수정되면 이 스냅샷과 비교해서 변경을 감지해서 알아서 sql을 보내준다.
엔티티 삭제
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.beans.PersistenceDelegate;
import java.util.List;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); //db와 연결도 다 됨.
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
//code
try {
Member memberA = em.find(Member.class, 1L);
//엔티티 데이터 삭제
em.remove(memberA);
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
emf.close();
}
}
플러시
영속성 컨텍스트의 변경내용을 데이터베이스에 반영하는 것
플러시 발생될 때
- 데이터가 수정되었을 때 (변경감지)
- 수정된 엔티티 쓰기 지연 SQL저장소에 등록될 때
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송할 때
영속성 컨텍스트를 플러시하는 방법
- em.flush() // 직접 호출
- 트랜잭션 커밋 // 플러시 자동 호출
- JPQL 쿼리 실행 // 플러시 자동 호출
플러시는 영속성 컨텍스트를 비우지 않는다.
영속성 컨텍스트의 변경내용을 테이터베이스에 동기화하는 것이다.
'Spring > JPA' 카테고리의 다른 글
[JPA] 다양한 연관 관계 매핑 (0) | 2021.03.07 |
---|---|
[JPA] *중요* 양방향 연관관계와 연관관계의 주인 (0) | 2021.03.07 |
[JPA] 연관관계 매핑 - 단방향 연관관계 ( 객체지향적으로 설계하는 방법 ) (0) | 2021.03.06 |
[JPA] 아주 간단한 쇼핑몰 만들기 (0) | 2021.03.06 |
[JPA] 엔티티 매핑 (0) | 2021.03.06 |
댓글