
공통 질문
트러블슈팅 및 실무
- JPA 사용 시 발생할 수 있는 LazyInitializationException의 원인과 해결 방법은 무엇인가요?
- 영속성 컨텍스트와 데이터베이스의 동기화 타이밍은 언제 이루어지나요?
- EntityManager와 Spring Data JPA의 Repository 간의 차이점은 무엇인가요?
- @Transactional의 동작 원리와 JPA에서의 역할은 무엇인가요?
- 실무에서 JPA를 사용할 때 주의해야 할 점과 흔히 발생하는 실수는 무엇인가요?
- JPA를 사용할 때 Native Query를 사용하는 이유와 주의점은 무엇인가요?
- JPA로 대규모 데이터를 처리할 때 고려해야 할 점은 무엇인가요?
- 읽기 전용 트랜잭션(ReadOnly Transaction)에서 JPA가 어떻게 동작하는지 설명해주세요.
- JPA Auditing 기능(@CreatedDate, @LastModifiedDate 등)의 원리와 사용 사례를 설명해주세요.
- JPA에서 다중 데이터베이스(Multi-Database)를 설정하려면 어떻게 해야 하나요?
- JPA 사용 시 발생할 수 있는 LazyInitializationException의 원인과 해결 방법은 무엇인가요?
원인
- FetchType.LAZY로 설정된 연관 엔티티를 **영속성 컨텍스트(EntityManager)**가 종료된 이후에 접근하려고 할 때 발생합니다.
- 예: @ManyToOne(fetch = FetchType.LAZY)로 설정된 필드에 데이터가 로드되지 않았는데, 트랜잭션 밖에서 접근하려 하면 예외 발생.
해결 방법
Fetch Join 사용: JPQL이나 QueryDSL에서 JOIN FETCH로 필요한 연관 데이터를 한 번에 가져옵니다.
@Query("SELECT p FROM Product p JOIN FETCH p.category WHERE p.id = :id")
Product findProductWithCategory(@Param("id") Long id);
@Transactional로 트랜잭션 유지: Lazy 로딩이 필요한 부분에서 트랜잭션을 유지합니다.
@Transactional
public Product findProduct(Long id) {
Product product = productRepository.findById(id).orElseThrow();
product.getCategory().getName(); // Lazy 로딩 처리
return product;
}
EntityGraph 사용: 연관 엔티티를 즉시 로딩하도록 지정합니다.
@EntityGraph(attributePaths = {"category"})
Product findById(Long id);
DTO Projection
- 필요한 데이터만 조회하도록 설계합니다.
@Query("SELECT new com.example.dto.ProductDto(p.name, s.stockQuantity) " +
"FROM Product p JOIN p.stock s WHERE p.id = :id")
ProductDto findProductDtoById(@Param("id") Long id);
@Query("SELECT new com.example.dto.ProductDto(p.name, c.name)
FROM Product p JOIN p.category c WHERE p.id = :id")
ProductDto findProductDto(@Param("id") Long id);
Hibernate.initialize() 사용
- 강제로 초기화합니다.
Product product = productRepository.findById(id).orElseThrow();
Hibernate.initialize(product.getStock());
2. 영속성 컨텍스트와 데이터베이스의 동기화 타이밍은 언제 이루어지나요?
- em.flush() 호출 시: 영속성 컨텍스트의 변경 사항이 데이터베이스에 반영됩니다.
- 트랜잭션 커밋 시: flush()가 자동으로 호출됩니다.
- JPQL 쿼리 실행 시: JPQL 실행 전에 flush()가 호출되어 변경 내용을 반영합니다.
flush 동작
- 변경된 엔티티 감지(Dirty Checking).
- 변경 내용을 SQL로 변환.
- SQL을 데이터베이스에 전달.
3. EntityManager와 Spring Data JPA의 Repository 간의 차이점은 무엇인가요?

4. @Transactional의 동작 원리와 JPA에서의 역할은 무엇인가요?
동작 원리
- Spring의 AOP(Aspect-Oriented Programming)를 사용해 메서드 실행 전후에 트랜잭션을 관리합니다.
- 프록시 객체를 생성하여 트랜잭션 시작 및 종료 로직을 삽입합니다.
- 메서드가 성공적으로 완료되면 커밋, 예외가 발생하면 롤백합니다.
JPA에서의 역할
- 트랜잭션이 시작될 때 영속성 컨텍스트를 초기화합니다.
- 트랜잭션 커밋 시 영속성 컨텍스트의 변경 사항을 데이터베이스에 반영합니다.
- 지연 로딩을 지원합니다. 트랜잭션 범위 내에서만 Lazy Loading이 동작합니다.
- 트랜잭션 범위 내에서 영속성 컨텍스트 관리.
- 트랜잭션 종료 시 플러시(Flush)와 커밋 수행.
- 예외 발생 시 롤백 처리.
5. 실무에서 JPA를 사용할 때 주의해야 할 점과 흔히 발생하는 실수는 무엇인가요?
N+1 문제: 연관 엔티티를 Lazy 로딩으로 설정하고 반복문에서 접근 시 발생.
- 해결: Fetch Join, EntityGraph 사용.
LazyInitializationException
- 트랜잭션 범위에서 데이터를 처리하거나, 필요한 데이터를 명시적으로 로딩합니다.
영속성 컨텍스트 누수:
- @Transactional 범위가 길 경우 메모리 누수 가능.
대규모 데이터 처리
- 페이징 처리, 대량 삭제/업데이트 시 JPQL 또는 Native Query를 사용합니다.
성능 최적화 부족:
- 대량 데이터 삽입 시 Batch Insert/Update 사용.
- hibernate.default_batch_fetch_size 설정으로 지연 로딩 최적화.
성능 문제
- 쿼리 성능 분석 및 캐싱 전략(EhCache, Redis 등) 활용.
DTO와 엔티티 혼용:
- 비즈니스 로직에 엔티티 직접 사용은 지양. DTO 사용 권장.
필드 접근 문제:
- 무조건 Getter/Setter 사용. 필드 직접 접근 금지.
1. Native Query를 사용하는 이유와 주의점
사용 이유
- 복잡한 SQL 쿼리 작성이 필요할 때.
- 성능 최적화가 필요할 때.
- JPA에서 지원하지 않는 특정 데이터베이스 기능을 사용할 때.
주의점
- 데이터베이스 종속성 증가: 특정 DB에 종속될 가능성.
- 조회 결과 매핑: 엔티티 매핑이 어렵거나 복잡할 수 있음.
- SQL Injection 방지를 위해 반드시 파라미터 바인딩을 사용해야 함.
- JPQL과 통합 어려움: JPQL에서 제공하는 객체지향적 기능 사용 불가.
7. JPA로 대규모 데이터를 처리할 때 고려해야 할 점은 무엇인가요?
페이징 처리
- Pageable을 사용하거나, LIMIT/OFFSET을 활용합니다.
배치 처리
- Hibernate의 Batch Insert/Update를 활용합니다.
spring.jpa.properties.hibernate.jdbc.batch_size=30
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
메모리 관리
- em.clear()를 주기적으로 호출하여 영속성 컨텍스트를 비웁니다.
Streaming:
- 대량 데이터를 한 번에 조회하지 않고 스트림 형태로 처리.
@Query("SELECT p FROM Product p")
Stream<Product> findAllByStream();
8. 읽기 전용 트랜잭션(ReadOnly Transaction)에서 JPA가 어떻게 동작하는지 설명해주세요.
@Transactional(readOnly = true):
- 데이터베이스에서 쓰기 작업을 막습니다.
- Hibernate는 영속성 컨텍스트를 초기화하지만, 변경 감지(Dirty Checking)를 비활성화하여 성능을 향상시킵니다.
특징
- 읽기 작업만 수행하며, 변경 감지(Dirty Checking) 비활성화.
- 성능 최적화: 영속성 컨텍스트가 최소한으로 동작.
@Transactional(readOnly = true)
public List<Product> findProducts() {
return productRepository.findAll();
}
9. JPA Auditing 기능(@CreatedDate, @LastModifiedDate 등)의 원리와 사용 사례를 설명해주세요.
- Spring Data JPA의 Auditing 기능을 통해 엔티티 생성 및 수정 시점에 자동으로 날짜를 기록합니다.
- @CreatedDate, @LastModifiedDate 등을 사용하여 엔티티의 생명주기 이벤트에 따라 데이터를 설정합니다.
- Spring Data JPA의 AuditingEntityListener가 엔티티의 생성/수정 시점을 자동으로 기록.
- Hibernate의 라이프사이클 이벤트를 활용.
@EntityListeners(AuditingEntityListener.class)
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@CreatedDate
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime lastModifiedDate;
}
10. JPA에서 다중 데이터베이스(Multi-Database)를 설정하려면 어떻게 해야 하나요?
각 데이터베이스에 대한 DataSource 설정
@Bean
@Primary
@ConfigurationProperties("app.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("app.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
EntityManagerFactory 설정, EntityManager 설정
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(primaryDataSource())
.packages("com.example.primary")
.persistenceUnit("primary")
.build();
}
@Bean
public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(secondaryDataSource())
.packages("com.example.secondary")
.persistenceUnit("secondary")
.build();
}
@Primary
@Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean primaryEntityManager(
EntityManagerFactoryBuilder builder,
@Qualifier("primaryDataSource") DataSource dataSource) {
return builder.dataSource(dataSource).packages("com.example.primary").build();
}
트랜잭션 설정
@Primary
@Bean
public PlatformTransactionManager primaryTransactionManager(EntityManagerFactory primaryEntityManagerFactory) {
return new JpaTransactionManager(primaryEntityManagerFactory);
}
@Bean
public PlatformTransactionManager secondaryTransactionManager(EntityManagerFactory secondaryEntityManagerFactory) {
return new JpaTransactionManager(secondaryEntityManagerFactory);
}
Repository 설정:
@EnableJpaRepositories(
basePackages = "com.example.primary",
entityManagerFactoryRef = "primaryEntityManagerFactory"
)
public class PrimaryConfig {}
'학습 기록 (Learning Logs) > CS Study' 카테고리의 다른 글
[Note]In-memory cache-basic (0) | 2024.12.16 |
---|---|
Fetch Join (0) | 2024.12.12 |
JPA-advanced-question (0) | 2024.12.12 |
JPA-optimized-performance (0) | 2024.12.12 |
JPA-features (0) | 2024.12.12 |