Java/JPA

JPA?

재심 2022. 10. 30. 14:25

JPA: 인터페이스

Hibernate: JPA인터페이스의 구현체.  

 

[JPA Components]

EntityManager

JPA 인터페이스의 일부로 자바 객체 ("@Entity")를 DB에 저장된 데이터와 맵핑 해주는 ORM 기술을 정의한 인터페이스

"@Entity" 어노테이션을 달고 있는 Entity 객체들을 관리하며 실제 DB테이블과 맵핑하여 데이터를 조회/수정/저장 하는 기능을 수행한다.

PersistenceContext라는 논리적인 영역을 두어 내부적으로 Entity의 생애주기를 관리한다.

 

Entity의 생애주기

New

처음 생성되어 아직 EntityManager의 관리를 받지 않는 상태. 즉 순수한 자바 객체 상태라고 보면 된다.

Managed

EntityManager에 의해 관리되고 있는 단계. 

EntityManager에서 persist() 메서드를 호출하거나 JPQL로 쿼리된 Entity 객체는 Managed 단계가 된다. 

managed 단계가 되면 Persistence Context에 일종의 캐싱상태로 놓이게 된다. 

Detached

EntityManager가 더 이상 관리하지 않는 상태로 managed 상태에서 EntityManager로부터 분리된 상태

Removed

EntityManager의 Persistence Context에서 삭제된 상태.

Detached와 달리 Removed 상태가 되면 DB에 맵핑된 데이터도 함께 사라진다.

 

@Repository
public class JpaRepository {
 
    @PersistenceContext
    private EntityManager em; // 바로 요놈!
     
    public Long save(Member member) { // 1. new 상태
        em.persist(member); // 2. managed 상태
        em.detach(member); // 3. detached 상태
        return member.getId();
    }
}

[EntityManager의 특징]

EntityManager는 데이터베이스와 어플리케이션 사이에 위치하며 편리한 기능들을 제공한다.

First Level Cache

EntityManager는 Persistence Context에 등록된 Entity객체의 "@Id" 어노테이션이 붙은 필드값을 이용해 Map<Id,Entity> 형태로 저장한다. 

이후 데이터 조회를 요청하면 캐싱된 Entity가 있는지 확인하여 데이터가 존재하면 DB에 쿼리를 전송하지 않고 캐싱된 Entity를 반환하기 때문에 쿼리 성능이 최적화된다.

Identity

EntityManager는 내부적으로 Entity를 저장한다. 그러므로 동일한 Entity를 한 번 더 요청하면 동일한 Enitity를 반환하는 것을 보장한다. 

Write-Behind

EntityManager는 실제 트랜잭션이 커밋되기 전까지 발생한 쿼리를 모아서 commit한다. 

이 방식은 데이터를 처리하다가 롤백해야될 때 용이할 수 있으며 네트워크 비용을 줄일 수 있다. 

Dirty Check

Persistent Context에 등록된 Entity의 수정이 발생하면 First Level Cache와의 비교를 통해 알아서 UPDATE쿼리를 수행한다. 

Lazy Loading

Entity에 직접 조회하는 시점에서 쿼리를 실행하는 방식 

 

[EntityManagerFactory]

EntityManagerFactory는 EntityManager를 생성하는 클래스이다.

구현방식은 Container-Managed 방식과 Application-Managed 방식으로 구분된다.

 

EntityManagerFactory는 클라이언트의 요청이 올 때 마다 (thread가 생성될 때 마다) EntityManager를 생성하며, 내부적으로 DB커넥션 풀을 이용해서 DB에 접근한다. 

DB당 딱 하나만 생성해야 한다. Multi-DB인 경우 EntityManagerFactory를 여러개를 생성한 후 각자 EntityManager를 생성하면 되는듯하다. 

thread간에 공유하면 안되고 트랜잭션이 수행된 후에는 반드시 닫고 DB커넥션을 반환해야 한다. 

 

출처: https://jaeho214.tistory.com/73

Container-Managed

스프링 컨테이너에 등록된 EntityManagerFactory에서 EntityManager를 생성하여 주입하는 방식.

close() 같은 경우도 컨테이너에서 알아서 해준다고 한다.

 

A simple but very visible difference is that you must call close() on an application-managed entity factory.

When you use a container-managed one, the container does this for you.

Application-Managed

스프링 컨테이너에 등록된 EntityManagerFactory를 주입받아 어플리케이션에서 직접 EntityManager를 생성하여 사용하는 방식.

소스에서 EntityManagerFactory를 선언하는 경우가 여기에 해당된다. 

 

동시성 (Concurrency)

엔티티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 생기므로 스레드 간에 절대 공유되면 안된다.

동시성이란 유저가 체감하기에는 스레드들이 동시에 수행되는 것처럼 보이지만 사실은 유저가 체감할 수 없는 짧은 시간단위로 작업들을 번갈아가며 수행하는 것이다. 

 

싱글코어에서 멀티 스레드를 구현할 때 나오는 개념이다. 

즉, 각 스레드들이 동시에 동작하는 것 같지만 알고보면 스레드들이 아주 짧은시간마다 번갈아가면서 작업을 수행하는 것이다. 

 

병렬성 (Parallelism)

멀티 코어에서 여러 스레드가 동시에 동작한다.

→ 내가 수정하고 있는데, 다른 스레드에서 해당 데이터를 수정해버리면 안된다.

 

→ 엔티티 매니저는 하나를 공유하면 안되고, 상황에 따라서 계속해서 만들어주어야 한다.

 

 

[EntityManagerFactory 생성방법]

LocalEntityManagerFactoryBean

JPA스펙의 JavaSE 기동방식을 이용해 EntityManagerFactory를 생성

스프링을 본격적으로 사용하기에는 많은 제약사항이 있다고 함.

스프링의 빈으로 등록한 Datasource 사용불가

 

LocalContainerEntityManagerFactoryBean

스프링이 직접 제공하는 컨테이너 관리 EntityManager를 위한 EntityManagerFactory를 생성.

스프링에 기반하는 어플리케이션 환경에서 전체 JPA기능을 활용하려면 이것을 통해 Factory를 생성하는 것이 바람직하다고 한다. 

 

트랜잭션 매니저

  • 컨테이너가 관리하는 EntityManager 방식에는 반드시 필요함.

[Persistent Context (영속성 컨텍스트)]

EntityManager가 생성되면 1:1로 영속성 컨텍스트가 생성된다.

하지만 컨테이너 환경의 JPA에서는 여러 EntityManager가 하나의 영속성 컨텍스트를 공유하게 된다.

컨테이너 환경의 JPA란 Spring같이 개발자가 EntityManager를 직접생성하지 않고 컨테이너에 위임한 것을 말함.

Spring은 싱글톤 기반이기 때문에 속성값은 모든 thread가 공유하게 된다. → thread-safe하지 않다

But 스프링에서는 EntityManager를 Proxy를 통해서 감싸서 thread safe 하게 동작하도록 하게 한다고 한다.

 

여러 EntityManager를 사용해도 하나의 트랜잭션으로 묶이면 영속성 컨텍스트를  공유한다.

출처: https://jaeho214.tistory.com/73

같은 EntityManager를 사용해도 트랜잭션에 따라 접근하는 영속성 컨텍스트가 다르다.

따라서 같은 EntityManager를 호출해도 접근하는 영속성 컨텍스트가 다르므로 멀티스레드에 안전하다고 한다.

 

출처: https://jaeho214.tistory.com/73

 

[참조]

이 문서를 토대로 작성함.

https://velog.io/@koo8624/Spring-EntityManager

 

[Spring] Entity, EntityManager and Persistence Context

스프링에서 JPA를 다루다보면 EntityManager 객체를 만나게 된다.EntityManager는 JPA 인터페이스의 일부로, 자바 객체(@Entity)를 DB에 저장된 데이터와 맵핑해주는 ORM 기술을 정의한 인터페이스이다. 이번

velog.io

 

SpringBoot 멀티 데이터소스 예제: https://www.skyer9.pe.kr/wordpress/?p=2313

 

Spring Boot JPA 멀티 데이타소스 – 상구리의 기술 블로그

Spring Boot JPA 멀티 데이타소스 목표 두개 이상의 데이타소스를 설정합니다. application.yml 기존 하나의 데이타소스 설정에서 두개 이상의 데이타소스를 설정할 수 있습니다. url 설정과 jdbc-url 이 필

www.skyer9.pe.kr

EntityManagerFactory, EntityManager, Persistence Context: https://jaeho214.tistory.com/73

 

[SPRING] JPA의 영속성 컨텍스트

영속성 관리에서 가장 중요한 것은 2가지이다. 객체와 관계형 데이터베이스간의 매핑 영속성 컨텍스트 ( JPA 내부 동작 ) EntityManagerFactory와 EntityManager 클라이언트의 요청이 올때 마다 ( 즉, thread가

jaeho214.tistory.com

토비의 스프링 JPA 정리: https://milenote.tistory.com/171

 

[토비의 스프링 - Vol.2] 2장 - 2.4 JPA

2.4 JPA Java Persistent API의 약자로 EJB 3.0과 함꼐 등장한 JavaEE와 JavaSE를 위한 영속성 관리와 O/R 매핑을 위한 표준 기술 오브젝트를 중심으로 개발하는 자바 같은 언어를 통해 접근하려면 불편한 점이

milenote.tistory.com

EntityManager가 Container-Managed 인지 알려줌: https://www.baeldung.com/hibernate-entitymanager

 

Guide to the Hibernate EntityManager | Baeldung

Have a look at the EntityManager class and its use in Hibernate

www.baeldung.com