영속성 컨텍스트
영속성 컨텍스트란 엔티티를 영구 저장하는 환경이라는 뜻이다.
엔티티 매니저를 통해 영속성 컨텍스트에 접근하여 엔티티를 관리하고 데이터베이스에 저장할 수 있다.
- entityManager.persist(entity) : 엔티티 매니저를 사용해 엔티티를 영속성 컨텍스트에 저장한다.
엔티티의 생명주기
- 비영속 (new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
- 영속 (managed) : 영속성 컨텍스트에 관리되는 상태
- 준영속 (detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
- 삭제 (removed) : 삭제된 상태
비영속
객체를 생성했지만 영속성 컨텍스트에서 관리하지 않는 상태를 의미한다.
//객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
영속
생성된 객체를 엔티티 매니저를 이용하여 트랜잭션 안에서 객체를 영속성 컨텍스트에 저장한 상태를 의미한다.
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//객체를 저장한 상태(영속)
em.persist(member);
준영속
영속성 컨텍스트에 저장된 엔티티를 분리한 상태를 의미한다.
더 이상 영속성 컨텍스트가 엔티티를 관리하지 않는다.
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);
삭제
엔티티를 영속성 컨텍스트와 DB에서 삭제한 상태를 의미한다.
//객체를 삭제한 상태(삭제)
em.remove(member);
영속성 컨텍스트의 이점
- 1차 캐시
- 동일성(identity) 보장
- 트랜잭션을 지원하는 쓰기 지연 (transactional write-behind)
- 변경 감지(Dirty Checking)
- 지연 로딩(Lazy Loading)
1차 캐시
영속성 컨텍스트의 내부에는 1차 캐시라는 곳이 있다.
엔티티의 @ID와 인스턴스를 key, value로 캐시에 저장한다.
동일한 트랜잭션 내에서 엔티티를 조회할 때 캐시가 사용된다.
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
//1차 캐시에 저장됨
em.persist(member);
//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");
엔티티를 조회할 때 먼저 1차 캐시에서 저장된 동일한 엔티티가 있는지 찾아본다.
있을 경우 DB에 쿼리를 날리지 않고 캐시에서 엔티티를 가져오고
없을 경우 DB에서 엔티티를 찾아 1차 캐시에 저장하고 객체를 반환한다.
동일성 보장
같은 트랜잭션 내에서 동일한 엔티티를 조회할 경우 동일하다는 것이 보장된다.
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //동일성 비교 true
트랜잭션을 지원하는 쓰기 지연
같은 트랜잭션 내에서 em.persist를 호출해도 바로 데이터베이스에 쿼리를 보내는 것이 아닌
트랜잭션을 커밋할 때 한꺼번에 쿼리를 보낸다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
em.persist를 호출하면 생성된 Insert SQL은 쓰기 지연 SQL 저장소라는 곳에 저장되고
저장된 SQL은 트랜잭션을 커밋할 때 DB에 반영되게 된다.
변경 감지
DB의 엔티티를 수정할 때 엔티티를 조회하여 수정하기만 하면 자동으로 DB에 반영된다.
transaction.begin(); // [트랜잭션] 시작
// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
//em.update(member) 따로 update하지 않아도 된다.
transaction.commit(); // [트랜잭션] 커밋
영속성 컨텍스트에 엔티티가 관리되어 1차 캐시에 저장될 때 스냅샷이라는 것이 같이 생성된다.
스냅샷에는 들어올 때의 엔티티가 동일하게 저장되어 있는데
만약 엔티티가 기존의 스냅샷과 다르면 UPDATE SQL를 생성한다.
출처 : https://www.inflearn.com/course/ORM-JPA-Basic/dashboard
'JPA' 카테고리의 다른 글
[JPA] 프록시와 지연로딩 (2) | 2023.03.05 |
---|---|
[JPA] @MappedSuperclass 사용법 (0) | 2023.03.03 |
[JPA] 상속관계 매핑 (0) | 2023.03.03 |
[JPA] 연관관계 매핑 (0) | 2023.02.28 |
[JPA] 기본 키 매핑 방법 (0) | 2023.02.27 |