PersistenceContext와 PersistenceUnit의 차이
PersistenceContext란?
PersistenceContext는 JPA에서 EntityManager를 관리하는 범위를 의미한다. 쉽게 말해, 데이터베이스와의 작업을 관리하는 영속성 컨텍스트를 나타낸다.
- 특징
- 영속성 컨텍스트는 엔티티의 생명 주기를 관리한다.
- 1차 캐시를 사용하여 성능을 최적화하며, 동일한 트랜잭션 내에서 동일한 엔티티를 조회하면 데이터베이스를 재조회하지 않는다.
- @PersistenceContext 어노테이션을 통해 주입받을 수 있다.
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
public class UserService {
@PersistenceContext
private EntityManager entityManager;
public User findUser(Long userId) {
return entityManager.find(User.class, userId); // 1차 캐시를 활용
}
}
PersistenceUnit이란?
PersistenceUnit은 persistence.xml에 정의된 EntityManagerFactory를 관리하는 단위다.
- 특징
- 애플리케이션에서 여러 데이터베이스를 사용하는 경우, 각각에 대해 별도의 PersistenceUnit을 정의할 수 있다.
- @PersistenceUnit 어노테이션을 통해 EntityManagerFactory를 주입받아 사용한다.
- EntityManager와 달리, EntityManagerFactory는 스레드 세이프하다.
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.PersistenceUnit;
public class UserService {
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
public User findUser(Long userId) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
return entityManager.find(User.class, userId);
}
}
PersistenceContext와 PersistenceUnit 차이 요약
정의 | 영속성 컨텍스트(EntityManager 관리 범위) | persistence.xml에 정의된 EntityManagerFactory 관리 |
주요 어노테이션 | @PersistenceContext | @PersistenceUnit |
역할 | 트랜잭션 범위 내 엔티티 생명주기 관리 | EntityManagerFactory 주입 및 관리 |
스레드 세이프 여부 | 스레드에 안전하지 않음 | 스레드 세이프 |
즉 스레드 세이프(Thread-safe)하지 않기에, 동시에 여러 스레드에서 접근할 경우 @PersistenceContext 는 데이터 불일치나 오류가 발생할 가능성이 있다.
@PersistenceContext로 주입된 EntityManager는 트랜잭션 범위 내에서 작동하며, 각 트랜잭션마다 고유의 EntityManager 인스턴스가 생성된다. 따라서 하나의 EntityManager를 여러 스레드에서 동시에 사용하지 않는다. 이를 통해 스레드 세이프 문제를 방지 하지만, EntityManager 자체는 설계상 스레드에 안전하지 않습니다.
반면, @PersistenceUnit으로 주입된 EntityManagerFactory는 스레드 세이프하다. EntityManagerFactory는 EntityManager 인스턴스를 생성하는 팩토리 역할만 하며, 여러 스레드가 동시에 접근하더라도 안전하게 동작하도록 설계되어 있다.
속도 비교: PersistenceContext vs PersistenceUnit
- @PersistenceContext:
- 트랜잭션 범위 내에서 EntityManager를 사용하기 때문에, 트랜잭션마다 효율적으로 엔티티 생명주기를 관리한다.
- 주로 데이터베이스 작업이 트랜잭션 단위로 처리되므로 속도가 빠르고 일관성이 보장된다.
- @PersistenceUnit:
- EntityManagerFactory는 EntityManager를 생성하는 데 필요한 리소스를 초기화하고 관리한다.
- EntityManagerFactory 생성은 비용이 크기 때문에, 일반적으로 애플리케이션 전역에서 하나만 생성하여 재사용한다.
- @PersistenceUnit은 EntityManagerFactory를 직접 다루므로 초기화 비용은 높지만, 이후에 새로운 EntityManager를 생성하는 데 유용하다.
간단 정리
- @PersistenceUnit:
- 전체를 초기화하고 관리하는 역할
- 애플리케이션 전역적으로 한 번만 초기화하고 여러 스레드에서 재사용하는 경우에 유리
- EntityManagerFactory 생성 비용이 크기 때문에, 빈번히 변경해야 하는 상황에서는 비효율적일 수 있다.
- 사용 예: 다수의 스레드에서 독립적인 EntityManager 인스턴스를 만들어야 하는 경우.
- @PersistenceContext:
- 트랜잭션 범위 내에서 엔티티 생명주기를 관리
- 필요한 순간마다 새로운 EntityManager를 생성하고 폐기하므로, 개별 트랜잭션 단위로 데이터를 처리하는 데 적합
- EntityManager는 트랜잭션에 특화되어 동작하기 때문에, 짧고 빈번한 데이터 조작에 더 효율적
- 사용 예: 트랜잭션 단위의 CRUD 작업.
.. etc 추가 학습
@Transactional(readOnly = true)의 효과
@Transactional(readOnly = true)란?
@Transactional(readOnly = true)는 트랜잭션 내에서 읽기 작업만 수행하겠다는 선언이다. JPA는 이를 통해 성능 최적화를 지원한다.
- 특징
- 트랜잭션은 여전히 활성화되지만, 쓰기 관련 작업은 제한된다.
- 데이터베이스에 따라 읽기 전용 트랜잭션을 활용해 잠금(Lock) 방식을 최적화한다.
- 스프링 데이터 JPA에서 조회 메서드의 기본 트랜잭션 설정으로 사용된다.
예시 코드
1. 기본 설정
다음은 일반적인 읽기 트랜잭션의 예다.
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Transactional(readOnly = true)
public User findUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found"));
}
}
2. 성능 차이 확인
만약 @Transactional(readOnly = true)를 설정하지 않으면, 다음과 같은 성능 문제가 발생할 수 있다.
// @Transactional 설정 없음
@Transactional
public User findUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found"));
}
// @Transactional(readOnly = true) 설정
@Transactional(readOnly = true)
public User findUserByIdOptimized(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found"));
}
- readOnly가 없는 경우 JPA는 데이터베이스에 잠금을 걸 수도 있다.
- readOnly = true를 사용하면 조회 작업에 최적화된 트랜잭션 전략을 사용한다.
주의점
- 쓰기 작업은 제한됨
- readOnly = true 트랜잭션 내에서 엔티티를 변경해도 데이터베이스에 반영되지 않는다.
- 읽기 전용 트랜잭션의 활용성
- 주로 조회만 수행하는 서비스 메서드에 적용한다.
총 정리
PersistenceContext와 PersistenceUnit 차이
1. PersistenceContext는 JPA에서 EntityManager를 관리하는 영속성 컨텍스트로, 엔티티 생명 주기와 1차 캐시를 관리한다.
2. PersistenceUnit은 persistence.xml에 정의된 EntityManagerFactory를 관리하며, 여러 데이터베이스를 사용하는 경우 유용하다.
3. @PersistenceContext는 EntityManager를, @PersistenceUnit은 EntityManagerFactory를 주입받는다.
4. PersistenceContext는 트랜잭션 범위 내에서 작동하며, PersistenceUnit은 스레드 세이프하다.
@Transactional(readOnly = true)의 효과
1. @Transactional(readOnly = true)는 트랜잭션 내에서 읽기 작업만 수행하도록 최적화해, 잠금(Lock) 없이 조회 성능을 향상시킨다. 주로 조회 메서드에 사용되며, 데이터 변경 작업은 허용되지 않는다.
2. 읽기 전용 설정을 통해 데이터베이스의 불필요한 부하를 줄이고, JPA의 성능을 극대화할 수 있다.
'JAVA > Spring' 카테고리의 다른 글
Querydsl로 효율적으로 JPA 조건 쿼리 작성하기 (1) | 2025.01.21 |
---|---|
@RequiredArgsConstructor와 @AllArgsConstructor 비교 [spring 의존성 주입] (0) | 2025.01.17 |
Spring WebSocket의 기본 개념과 [클라이언트-서버] 연결 (0) | 2025.01.01 |
Jackson과 Lombok @Data 어노테이션을 이용한 JSON 데이터 처리 (0) | 2024.12.31 |
Java에서 ProcessBuilder와 클래스패스 설정에 대한 이해 (0) | 2024.12.30 |
댓글