영속성 콘텍스트
"엔티티를 영구 저장하는 환경"이라는 뜻
- 영속성 콘텍스트는 논리적인 개념이다.
- 눈에 보이지 않는다.
- 엔티티 매니저를 통해서 영속성 콘텍스트에 접근한다.
엔티티의 생명주기
비영속(new/transient) | 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태 |
영속(managed) | 영속성 컨텍스트에 관리 되는 상태 |
준영속(detached) | 영속성 컨텍스트에 저장되었다가 분리된 상태 |
삭제(removed) | 삭제된 상태 |
//객체를 생성한 상태(비영속)
Member member = new Member();
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//객체를 저장한 상태(영속)
em.persist(member);
//회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);
//객체를 삭제한 상태(삭제)
em.remove(member);
영속성 콘텍스트의 이점
1차 캐시
- 영속성 콘텍스트의 내부에 1차 캐시가 존재한다. (캐시값은 Id, Entity)
- 애플리케이션 전체가 공유하는 캐시가 아니라, 트랜젝션 하나에서 작동되는 캐시
만약 찾는 값이 1차 캐시에 존재하는 경우
- 저장한 이후에 조회를 할 때, 영속성 콘텍스트에서 먼저 1차 캐시를 찾는다.
- 있으면 캐시에 있는 값을 그냥 가져온다.
만약 찾는 값이 1차 캐시에 존재하지 않는 경우
- 없다면 DB에서 찾은 값을 1차 캐시에 저장시킨 후 반환한다.
동일성 보장
Item a = em.find(Item.class, "item1");
Item b = em.find(Item.class, "item1");
System.out.println(a == b); //동일성 비교 true
1차 캐시로 반복 가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공
트랜잭션을 지원하는 쓰기 지원
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
*모든 변경은 트랜잭션 내부에서 일어나야 한다.
단순히 persist, find... 를 하는 순간 sql문을 보내는 것이 아닌, commit시에 한 번에 보낸다.
변경 감지
영속콘텍스트에 존재하는 스냅숏과 비교하여 변경이 감지되었다면,
UPDATE SQL을 자동으로 생성해 준다.
따라서 아래와 같은 코드가 가능해진다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // [트랜잭션] 시작
// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
//em.update(member) 필요가없음
transaction.commit(); // [트랜잭션] 커밋
지연 로딩
- Eager(즉시 로딩) : 외래키로 연관관계가 매핑된 객체를 불러올 때 외래키를 기본키로 가지는 객체도 바로 불러오게 한다. 이때 추가로 가져온 객체는 프락시가 아닌 실제 객체이다.
- Lazy(지연 로딩) : 외래키로 표현시킨 객체는 프락시로 받아오고, 후에 필요할 때가 있다면 그때 해당 객체를 다시 불러온다.
- 즉시로딩은 어떤 쿼리문으로 나갈지 예측할 수 없기 때문에, 지연 로딩을 통해 하나의 객체만 온전하게 불러오기 더 안전해진다.
플러시
영속성 콘텍스트의 변경내용을 데이터베이스에 반영하는 것
플러시 발생
- 변경 감지
- 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
- 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송
영속성 콘텍스트를 플러시 하는 방법
- em.flush() - 직접 호출
- 트랜잭션 커밋 - 플러시 자동 호출
- JPQL 쿼리 실행 - 플러시 자동 호출
플러시는 영속성 콘텍스트를 비우지 않는다.
영속성 콘텍스트의 변경내용을 데이터베이스에 동기화한다.
'JPA' 카테고리의 다른 글
JPQL 사용법 (3) | 2023.01.09 |
---|---|
JPA의 데이터 타입 (3) | 2023.01.07 |
프록시 & 지연로딩 (0) | 2023.01.07 |
엔티티 매핑 (0) | 2023.01.06 |
JPA란 무엇인가? (7) | 2022.12.24 |