Be ready to study forever - 개발자 꿈나무
[JPA] 영속성 컨텍스트란? 본문
영속성 컨텍스트란?
영속성 컨택스트란 논리적 개념으로 JPA를 이해하는데 아주 핵심적인 개념이다. 영속성 컨탠스트는 DB에도 값을 저장하지만 자바 어플리케이션 내에도 영속성 컨택스트로 따로 데이터를 보관하게 된다. 이렇게 보관된 데이터는 영속성 컨텍스트의 관리를 받는다 라고 할 수 있다. 영속성 컨택스트에 접근하는 방법은 EntityManager로 접근하는데, 코드로 살펴보자면
EntityManagerFactory emf = Psersistence.createEntityManagerFactory("name"); //Static Method로 단 하나의 EntityManagerFactory만 생성
EntityManager em = emf.createEntityManager(); //EntityManager 생성
em.persist(member); //객체를 영속성 컨텍스트에 저장(영속성 컨택스트가 관리함)
대부분의 기능은 EntityManager가 제공하고, EntityManager로 영속성 컨텍스트에 접근하고 CRUD도 EntityManager로 작업하기 때문에 DB커낵션과 밀접한 관련이 있고 스레드간에 공유나 재사용을 하면 안 된다.
**이쯤에서 다시보는 EntityManagerFactory와 EnitityManager. EntityManagerFactory는 자버 어플리 케이션에 하나만 존재하며 EntityManager를 사용하고 버린다.
영속성 컨텍스트의 관리를 받는다는건 무슨말?
영속성 컨텍스트의 상태와 생명주기에 대해서 이해해야 한다. 영속성 컨텍스트 내에서 엔티티의 생명주기는 4가지로 나눌 수 있는데
- 비영속(new / transient)
객체(엔티티)를 생성했지만 em.persist(entityA)를 하지 않은 상태 (영속성 컨택스트는 비영속 상태에서는 엔티티를 보관하거나 변경에 대한 관리를 하지 않는다)
- 영속(managed)
em.persist(entityA)를 해서 영속성 컨택스트의 관리르 받는 상태로 영속성 컨텍스트는 해당 앤티티를 보관하고, 변경에 대해서 감지하고, 변경된 부분이 있다면(Update) 디비에도 update로 쿼리로 반영한다. 즉 말그대로 관리를 해준다~~이말이야.
- 준영속(detached)
영속성 컨택스트에 보관되어 있다가 분리되어서 현재는 관리를 하고 있지 않은 상태이지만 언제든 다시 영속성 컨택스트의 관리를 받을 수 있는 상태
- 삭제(removed)
삭제가 되어 영속성 컨택스트에서 더 이상 관리 하지 않는 상태(DB에서도 delete쿼리가 나가며 삭제된다)
영속성 컨텍스트의 사용시 이점은?
Anyways… 그렇다면 DB에 정보를 저장하면 될 것을 영속성 컨택스트에 왜 따로 보관하는 것일까?
이점)
- 1차 캐시
- 동일성 보장
- 트랙잭션을 지원하는 쓰기지연
- 변경 감지
- 지연로딩
등이 있다. 하나 하나씩 설명해 보자면
1차캐시
영속성 컨텍스트의 관리를 받는 객체(엔티티)는 1차 캐시라는 공간에 보관된다. 그러므로, 한번 저장된 객체는 다시 같은 정보를 찾아올 때 쿼리를 날릴 필요없이 영속성 1차캐시에서 해당 객체를 가져오게 된다.(물론 해당 객체가 1차 캐시에 존재하지 않을 경우, 쿼리를 날려 DB에서 긁어온 다음에 1차 캐시에 저장한다.)
이미 1차 캐시에 있는 객체를 다시 조회해 올 때(쿼리를 다시 안날려도됨)
1차 캐시에 찾은 객체가 없는 경우 DB에서 긁어와서 1차 캐시에 저장(추후에 재사용시에 다시 쿼리를 안날려도 됨)
동일성 보장
디비에서 쿼리를 날려서 객체에 담는다면 같은 엔티티를 DB에서 긁어왔다고 하더라도 객체의 주소값이 서로 다르기 때문에 ==연산시에 fasle가 나오게 된다.(equals()를 오버라이드해서 사용해야함 – ==연산은 객체의 주소값을 비교하기 때문에 쿼리를 날려서 가저온 데이터가 같다고 하더라도 new 연산으로 새로운 객체를 만들기 때문에 주소값이 다름)
** 위의 내용이 이해가 가지 않는다면 primitive타입과 referece타입의 차이점, ==과 equals의 차이점을 다시 보고오길 바람…
하지만, JPA의 경우 동일성, 즉 ==연산시 동일한 앤티티라면 true를 반환하게 되는데, 영속성 컨텍스트의 객체에 저장된 값을 가져오기 때문에 가능한 일이다.
트랙잭션을 지원하는 쓰기지연
EntityManager가 데이터를 입력, 수정할 때에는 트랜잭션 단위 안에서 입력, 수정을 할 수 있다. 즉, 영속성 컨텍스트에 보관되어 관리되는 객체들이 트랜잭션이 커밋 될 때 DB에 반영 되게 된다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
위에 코드를 확인하면 더 직관적으로 알게 될 수 있음
무튼, 트랜잭션시에 모든 데이터를 쿼리로 날리게 되면 좋은 점은, 쿼리를 한번에 묶어서 날리기 때문에 그때 그때 쿼리를 날리는 것 보다 최적화에 도움이 된다.
다이어그램처럼 쿼리를 쓰기지연 저장소에 생성해 두고 객체는 1차 캐시에 저장해 둔 다음에
커밋 시점에서 한번에 쿼리를 날려줌
변경감지
1차 캐시 안에는 사실 최초로 1차 캐시에 초기화 되었을때의 값을 저장하고 있다. 이것을 스냅샷 이라고 부르는데, 이 스냅샷과 현재 저장된 값이 다를 경우 update 쿼리를 생성하게 된다. 따라서 개발자는, 이미 영속성 컨택스트의 관리를 받는 객체에 대해서는 업데이트 쿼리를 날려줄 필요가 없다.
그림을 보면 이해가 훨씬 빠를 것!
알아 두어야 할 다른 기능들
- em.flush();
커밋이 되기 전에 쓰기지연 자정소에 저장된 쿼리를 날리고 싶다면 flush();를 쓰면 된다. 사실은 커밋 안에 flush();가 들어가 있다!
- em.clear();
영속성 컨택스트의 1차 캐시를 모두 비우는 행동으로 영속성 컨택스트를 초기화 한다.(때에 따라서 DB에서 다시 select쿼리르 긁어와야 할 때, 즉, 싱크를 맞출 때 필요함)
- em.close();
영속성 컨택스트를 종료함
- em.detach(entity);
해당 엔티티를 영속성 컨텍스트에서 분리시켜 준 영속 관계로 만든다
'Programming > JPA' 카테고리의 다른 글
[JPA] 고급 매핑 - 3 (0) | 2021.01.23 |
---|---|
[JPA] 다양한 연관관계 매핑-2 (0) | 2021.01.23 |
[JPA] 연관관계 매핑 기초 - 1 (0) | 2021.01.23 |
[JPA]실행하기 (0) | 2021.01.22 |
[JPA] JPA란? (0) | 2021.01.22 |