CS study/jpa 및 Hibernate

EntityManager와 @PersistenceContext (24.05.23)

블랑v 2024. 10. 1. 04:45
  1. EntityManager는 Bean으로 관리되는 싱글톤 객체이지만, 이것 자체를 사용할 수는 없다. 그 이유는 생성자 주입으로 이것을 사용한다고 해도, 여러 클래스에서 공유항 사용한다면 트랜잭션 간 내부 데이터가 꼬일 가능성이 높기 때문이다. (데이터 중복 및 무결성에 문제)
  2. @PersistenceContext를 사용한다면 이 EntityManager의 Bean 객체의 '프록시'를 만들게 된다. 각각의 트랜잭션마다 이 프록시 객체를 할당함으로써, 여러 트랜잭션이 동시에 실행되더라도 EntityManager 내부에서 관리되는 데이터의 무결성을 보장할 수 있게 된다. 각각의 트랜잭션이 독립적인 EM 프록시를 할당받기 때문이다.

정리

  1. EntityManager는 Bean으로 관리되는 싱글톤 객체이지만, 이것 자체를 사용할 수는 없다.
    • 이유: 생성자 주입으로 이를 사용한다고 해도, 여러 클래스에서 공유하게 되면 트랜잭션 간에 데이터가 꼬일 가능성이 높다. 이는 여러 클래스가 동일한 EntityManager 인스턴스를 사용하면 발생할 수 있는 문제로, 데이터의 중복 및 무결성 문제가 발생할 수 있다.
  2. @PersistenceContext를 사용한다면 이 EntityManager의 Bean 객체의 '프록시'를 만들게 된다.
    • 각각의 트랜잭션마다 이 프록시 객체를 할당함으로써, 여러 트랜잭션이 동시에 실행되더라도 EntityManager 내부에서 관리되는 데이터의 무결성을 보장할 수 있다. 각각의 트랜잭션이 독립적인 EntityManager 프록시를 할당받기 때문이다.
    • 트랜잭션이 시작될 때마다 스프링이 적절한 EntityManager 인스턴스를 할당하고, 트랜잭션이 끝나면 이를 해제한다. 따라서 트랜잭션 간에 EntityManager 인스턴스가 격리되어 동작한다.

보완 사항

  • **EntityManager**가 싱글톤으로 관리되지만, 스프링은 이를 직접 사용하지 않도록 하고 **@PersistenceContext**를 통해 프록시 객체를 생성하여 주입한다.
  • EntityManager 프록시는 스프링이 트랜잭션 범위 내에서 적절히 관리하며, 트랜잭션 컨텍스트 내에서 실제 EntityManager 인스턴스를 사용하도록 한다.
  • **@PersistenceContext**가 없는 경우, **EntityManager**는 트랜잭션 관리를 하지 않으므로, 여러 트랜잭션 간의 데이터 일관성이 보장되지 않는다. 이는 동시성 문제를 야기할 수 있다..

EntityManager와 @PersistenceContext에 대한 자세한 정리

1. EntityManager란 무엇인가?

  • EntityManager: JPA(Java Persistence API)의 핵심 인터페이스로, 엔티티의 생성, 읽기, 업데이트, 삭제(CRUD) 작업을 수행한다. 영속성 컨텍스트(Persistence Context)를 통해 엔티티의 상태를 관리하고, 데이터베이스와 상호작용을 담당한다.

2. EntityManager의 Bean 관리

  • 싱글톤 관리: 스프링은 **EntityManager**를 싱글톤 빈으로 관리한다. 하지만 직접 사용되지 않고, **@PersistenceContext**를 통해 주입된 프록시 객체를 사용한다.
  • 트랜잭션 관리: 트랜잭션마다 다른 EntityManager 인스턴스를 사용하여 데이터의 일관성과 무결성을 유지한다.

3. @PersistenceContext의 역할

  • 프록시 객체 생성: @PersistenceContext 어노테이션은 **EntityManager**의 프록시 객체를 생성하여 주입한다.
  • 트랜잭션 스코프: 각 트랜잭션마다 독립적인 EntityManager 인스턴스를 할당하여, 여러 트랜잭션이 동시에 실행되더라도 데이터가 꼬이지 않도록 한다.

4. @PersistenceContext의 중요성

  • 동시성 문제 방지: 직접 **EntityManager**를 사용하면 트랜잭션 간의 데이터가 공유되어 동시성 문제가 발생할 수 있다. **@PersistenceContext**를 통해 주입된 프록시 객체를 사용하면 이러한 문제를 방지할 수 있다.
  • 트랜잭션 컨텍스트 관리: 스프링은 **@PersistenceContext**를 사용하여 트랜잭션 범위 내에서 **EntityManager**를 관리하고, 트랜잭션이 종료되면 자동으로 **EntityManager**를 정리한다.

5. JPAQueryFactory와 EntityManager

  • JPAQueryFactory: QueryDSL을 사용하여 타입 안전한 쿼리를 작성하고 실행할 수 있도록 도와주는 클래스이다. 내부적으로 **EntityManager**를 사용하여 쿼리를 실행한다.
  • EntityManager 주입: **JPAQueryFactory**는 생성자 주입을 통해 **EntityManager**를 받는다. 이 **EntityManager**는 **@PersistenceContext**를 통해 주입된 프록시 객체이다.

6. 설정 예제

QueryDslConfig 설정

java코드 복사
@Configuration
public class QueryDslConfig {

    @Bean
    public JPAQueryFactory jpaQueryFactory(EntityManager em) {
        return new JPAQueryFactory(em);
    }
}

서비스 클래스에서의 사용 예제

java코드 복사
@Service
@RequiredArgsConstructor
public class CommonQueryServiceImpl implements CommonQueryService {
    private final JPAQueryFactory jpaQueryFactory;

    @Transactional
    public List<String> getSumElements() {
        QSum qSum = QSum.sum;
        return jpaQueryFactory.select(qSum.name)
                .from(qSum)
                .fetch();
    }
}

요약

  • EntityManager: JPA의 핵심 인터페이스로, 엔티티의 상태를 관리하고 데이터베이스와 상호작용.
  • @PersistenceContext: EntityManager의 프록시 객체를 생성하여 주입. 트랜잭션마다 독립적인 인스턴스를 사용하도록 하여 동시성 문제를 방지.
  • JPAQueryFactory: QueryDSL을 사용하여 쿼리를 작성하고 실행. 생성자 주입을 통해 EntityManager를 받아 사용.

위와 같은 설정을 통해, 스프링은 트랜잭션 범위 내에서 안전하게 **EntityManager**를 관리하며, **QueryDSL**을 사용한 쿼리 작성과 실행이 가능하다.