데이터를 영구히 저장하기 위한 환경으로, 애플리케이션과 DB사이에서 객체를 보관하는 일종의 가상 DB개념
동일성 보장
같은 트랜잭션 안에서 영속성 컨텍스트를 통해 받아온 객체는 담는 변수가 다르더라도 동등비교를 보장한다.
Member member1 = em.find(Member.class, "member1"); Member member2 = em.find(Member.class, "member1");
위의 코드는 같은 트랜잭션 내에서 == 비교시 true를 반환한다.
즉, EntityManager에 의해 같은 객체의 값을 받아온다.
변경감지
최초로 영속성 컨텍스트에 들어온 객체의 상태를 스냅샷의 형태로 저장하고, 실제 값인 entity와 스냅샷 값이 다르다면 쓰기 지연 쿼리 저장소에 update쿼리문을 추가하고 flush 호출 시점에 실행한다.
1차 캐시
가져오려는 객체의 key값으로 영속성 컨텍스트가 관리하고 있는 Entity를 호출할 수 있으면 1차 캐시에 있는 Entity를 반환해주어 불필요한 DB작업을 없애준다.
HashMap의 형태로 key-value값을 저장하고 있으며, Id어노테이션으로 지정된 key값을 찾을 수 있으면 바로 반환, 찾을 수 없다면 DB에서 가져와 캐시에 저장하고 반환한다.
save()의 경우 DB에서 해당 Id컬럼의 마지막 값을 받아와서 +1을하여 넘겨받은 Entity의 key값으로 세팅한다. (id값을 비워서 줘도 값을 자동으로 넣을 수 있는 이유)
쓰기 지연 쿼리 저장소
persist(entity) 메소드를 통해 Insert, merge(entity) 메소드를 통해 Update문 등 쿼리를 쌓아두고 트랜잭션 커밋 시점이나, 임의 flush과정을 통해 한 번에 실행시킬 수 있다. 커밋시 1차 캐시는 초기화 된다.
Transient / new(비영속)
영속성 컨텍스트나 DB와는 아직까지 전혀 관련 없는 상태로, 단순히 순수한 객체상태이다.
Persistent / Managed(영속)
영속성 컨텍스트에 의해 관리받는 상태로 persist와 merge 메소드를 통해 영속상태로 변경되어 영속성 컨텍스트에 저장된다.
Detached(준영속)
영속성 컨텍스트에 저장되었다가 분리된 상태로, 더 이상 영속성 컨텍스트가 제공하는 기능을 사용하진 못하지만 식별자는 가지고 있다는 특징이 있다.
em.detach(entity), em.clear(), em.close() 메소드를 통해 준영속 상태로 만들 수 있다.
Removed(제거)
영속성 컨텍스트와 DB에서 엔티티가 삭제된 상태로
- save() 메소드 호출
- Repository의 구현체인 simpleJpaRepository의 save() 실행
- isNew()로 받아온 Entity가 기존에 있는지 검사(Entity에 @Id 속성을 기반으로 1차 캐시 -> DB조회 순서로 가져옴)
4.만약 새로운 Entity라면 persist() 실행, 아니라면 merge() 실행
- persist(): INSERT 쿼리문이 쓰기 지연 쿼리 저장소에 저장됨(실행 x, 트랜잭션 commit시 최종실행)
- Auto Increment 속성인 idx값을 가져와서 1차 캐시에 저장된 Entity 객체를 Value로, idx를 key로 하는 HashMap형태의 구조로 DB에 저장하여 동기화 시킨다.
- Transaction commit 작업을 호출하여 flush 메소드를 통해 쌓인 쿼리를 실행하고 commit까지 완료하여 해당 트랜잭션의 작업을 마친다.
- 1차 캐시에 해당 Id를 키값으로 하는 Entity가 있으면 바로 반환, 수정사항이 있다면 update 쿼리 생성, Entity를 찾을 수 없다면 Insert 쿼리를 생성하기 때문에 삽입과 수정을 하나의 메소드(save)로 처리할 수 있다.
데이터 수정시
- save() 메소드 호출
- Repository의 구현체인 simpleJpaRepository의 save() 실행
- isNew()로 받아온 Entity가 기존에 있는지 검사(Entity에 @Id 속성을 기반으로 1차 캐시 -> DB조회 순서로 가져옴)
- 1차 캐시 or DB에 해당 id에 해당하는 값이 있다면 merge() 메소드 실행
- 변경사항이 있다면 UPDATE 쿼리문이 쓰기 지연 쿼리 저장소에 저장, 없다면 아무 작업도 하지 않음(실행 x, 트랜잭션 commit시 최종실행)
6. Auto Increment 속성인 idx값을 가져와서 1차 캐시에 저장된 Entity 객체를 Value로, idx를 key로 하는 HashMap형태의 구조로 DB에 저장하여 동기화 시킨다.
7. Transaction commit 작업을 호출하여 flush 메소드를 통해 쌓인 쿼리를 실행하고 commit까지 완료하여 해당 트랜잭션의 작업을 마친다.
데이터 삭제 및 조회도 동일한 방식으로 이루어진다.
영속성 컨텍스트, 플러시, 준영속 상태
영속성 컨텍스트
영속성 컨텍스트와 영속성 관리
영속성 컨텍스트의 전반적인 이해