티스토리 뷰
JPA를 사용하면서 영속성 컨텍스트에 대해 이해하지 못하면 항상 예기치 못한 사이드 이펙트를 만나곤 한다. 그래서 영속성 컨텍스트에 대해 공부하면서 간단히 정리해본 글이다.
클래스 수준 아키텍처
아래의 이미지는 JPA의 클래스 레벨 아키텍처 입니다. 여러가지 코어적인 JPA의 클래스와 인터페이스를 볼 수 있습니다.
EntityManagerFactory
- EntityManager 클래스의 팩토리 클래스입니다. 이 클래스로 EntityManager 클래스의 인스턴스를 생성하고 관리EntityManager
- 인터페이스 입니다. 객체에 대한 영속성 관리작업을 합니다. Query 인스턴스를 생성하는 팩토리 처럼 작동합니다.Entity
- 영속 객체입니다. 이 객체의 스펙에 의해서 데이터베이스에 기록될 객체입니다.EntityTransaction
- EntityManager와 일대일 관계입니다. 각각의 EntityManager들의 작업은 EntityTransaction 클래스에 의해서 유지된다.Persistence
- 이 클래스는 EntityManagerFactory 인스턴스를 생성하는 정적 메소드를 가지고 있다.Query
- 인터페이스로서 각각의 JPA 벤더에 의해 구현되며 각 기준에 충족하는 관계형 객체를 얻습니다.
EntityManagerFactory와 EntityManager
EntityManagerFactory는 하나만 생성해서 애플리케이션 전체에서 공유한다.
- 애플리케이션 로딩 시점에 딱 하나(DB당 하나)
EntityManager는 쓰레드간에 공유하면 안된다.(사용하고 버려야 한다).
- 클라이언트 요청 마다 하나
- DB 트랜잭션 단위로 생성하고 제거한다.
JPA의 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다.
EntityManager를 통해서 영속성 컨텍스트에 접근한다.
EntityManager와 영속성 컨텍스트
스프링 프레임워크와 같은 컨테이너 환경에서 N:1 관계를 가진다.
영속성 컨텍스트
영속성 컨텍스트(Persistence Context)란
Entity를 관리하고 영속화(영구 저장) 시키는 환경
- ex) EntityManager.persist(entity) : DB가 아닌 영속성 컨텍스트에 저장한다는 의미
논리적인 개념이므로 눈에 보이지 않는다.
- EntityManager를 통해서 접근하기 때문
애플리케이션과 DB사이에서 엔티티를 관리해주는 환경
영속
//객체를 생성한 상태(비영속) Order order = new Order(); order.setName("떡볶이"); order.setId(1L); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); //객체를 저장한 상태(영속) em.persist(order);
- 영속은 영속성 컨텍스트에서 관리하는 상태를 말한다.
1차 캐시 와 쓰기 지연 SQL
1차 캐시
Order order = new Order();
order.setId(1L);
order.setName("떡볶이);
//1차 캐시에 저장됨
em.persist(member);
//1차 캐시에서 조회
Order findOrder = em.find(Order.Class, 1L);
// DB에서 조회(영속성 컨텍스트에 존재하지 않으면)
Order findOrder = em.find(Order.class, 2L);
JPA를 통해
find
를 호출하면 다음과 같은 순서로 동작한다.- 1차 캐시에서 조회
- DB에서 조회(1차 캐시에 없다면)
DB로 부터 데이터를 가져오면 1차 캐싱에 저장해두고 동일 트랜잭션 안에서 컬렉션처럼 동작한다.
1차 캐시에서 조회
DB에서 조회
EntityManager는 트랜잭션 단위로 생성하고 제거한다. 즉 클라이언트의 요청당 하나의 EntityManager를 생성하고 지운다.
모든 클라이언트가 엔티티를 공유하도록 캐싱하는 것이 아니라, 한 요청에 대한 트랜잭션 안에서만 캐싱을 하는 것.
영속성 컨텍스트가 종료되기 전 까지는 엔티티가 영속성 컨텍스트에 남아있는다.(1차 캐시 사용 가능)
트랜잭션을 지원하는 쓰기 지연
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction(); //엔티티 매니저는 데이터 변경시 트랙잭션을 시작해야 한다.
transaction.begin(); // 트랜잭션 시작
em.persist(orderA);
em.persist(orderB);
//여기 까지 INSERT SQL을 DB에 보내지 않는다.
//커밋하는 순간 DB에 INSERT SQL을 보낸다.
transaction.commit();
//커밋
flush 할때 JDBC의 Batch 기능을 이용하여 한번에 쿼리를 날린다.
더티 체킹
변경 감지(엔티티 수정시 이를 체킹하여 영속적으로 수정하도록 하는 기능), 별도의 UPDATE 쿼리가 필요 없음
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // 트랜잭션 시작
//영속 엔티티 조회
Order order = em.find(Order.class, 1L);
//엔티티 데이터 수정
order.setName("장춘동 족발");
order.setPrice("20000");
transaction.commit(); // 커밋
변경을 감지하는 원리
영속 컨텍스트에서 DB로부터 데이터를 가져올 때 1차 캐시 안에 스냅샷을 찍어둔다.
그리고 추후에 트랙잭션 커밋되는 시점에 엔티티와 스냅샷을 비교한다.
비교하여 변경을 감지하여 UPDATE 쿼리를 생성하여 쓰기 지연 SQL 저장소에 저장한다.
스냅샷이란?
- 영속성 컨텍스트에 들어온 최초의 값을 기록 (DB로부터든(find)비영속으로 부터든(persist))
JPA의 목적이 컬렉션 다루듯 객체를 다루는 것
'JPA' 카테고리의 다른 글
[JPA] QueryDSL 기본 문법 알아보기 (0) | 2023.04.07 |
---|---|
[JPA] Auditing, Projections, Pageable 이해하기 (0) | 2023.03.30 |
[Java] JPA 최적화(완벽 요약) (0) | 2023.03.30 |
[JAVA]JPA N+1 문제란?(해결방안) (0) | 2023.03.29 |
Spring Boot JPA 핵심 요약(이거만 보면 이해한다) (0) | 2023.03.15 |
- Total
- Today
- Yesterday
- GIS
- thread
- jenkins
- 쓰레드
- spring mvc
- spring
- 데이터베이스
- database
- 다운로드
- db
- Index
- oauth2
- TCP
- DispatcherServlet
- mysql
- Spring Security
- 네트워크
- R-Tree
- 영속성 컨텍스트
- 인덱스
- 공간쿼리
- 논블로킹
- spring boot
- 스프링
- github
- jpa
- lock
- 비동기
- Excel
- java
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |