[CS]JPA관련 질문 및 답변1

Michelle Kim·2025년 3월 12일

CS-지식

목록 보기
7/15

JPA(Java Persistence API)란 무엇이며, 왜 사용하는가?

  • JPA(Java Persistence API)란?
    자바 애플리케이션에서 관계형 데이터베이스를 객체 지향적으로 다룰 수 있도록 하는 ORM(Object-Relational Mapping) 표준 인터페이스

  • JPA 사용하는 이유?

  1. SQL 대신 객체 중심 개발: SQL을 직접 작성하지 않고, 객체 조작만으로 데이터베이스를 관리할 수 있습니다. => JPA를 사용하면 비즈니스 로직이 RDBMS에 의존하는 것이 아니라, 자바 코드로 표현될 수 있기 때문
  2. 생산성 증가: CRUD 메서드 제공, 지연 로딩(Lazy Loading) 등으로 개발 속도가 향상됩니다.
  3. DB 종속성 감소: 특정 DB 벤더에 의존적이지 않으며, DB 변경 시 코드 수정이 최소화됩니다.
  4. 캐싱 및 성능 최적화: 1차 캐시, 쓰기 지연(Write-Behind) 등의 기능을 통해 성능이 향상됩니다.
  • 발전과정
    EJB- 엔티티 빈(자바표준) ➔ 하이버네이트(오픈소스) ➔ JPA(자바 표준)

ORM이란?

  • Objected-Relational Mapping(객체 관계 매핑)
  • 객체는 객체대로 설계
  • 관계형 데이터베이스는 관계형 데이터베이스대로 설계
  • ORM 프레임워크가 중간에서 매핑
  • 대중적인 언어에는 대부분 ORM 기술이 존재

JPA 영속성 컨텍스트의 이점(5가지)을 설명

영속성 컨텍스트란?:

  • 엔티티를 영구 저장하는 환경을 의미
  • DB에서 가져온 엔티티를 저장하는 첫번째 메모리 캐시 저장소
  • EntityManager 객체의 API로 관리할 수 있다
  • EntityManager.persist(entity);

영속성 컨텍스트를 쓰는 이유?
1. 1차 캐시: 조회가 가능하며 1차 캐시에 없으면 DB에서 조회하여 1차 캐시에 올려 놓습니다.
2. 동일성 보장: 동일성 비교가 가능합니다.(==)
3. 쓰기 지연: 트랜잭션을 지원하는 쓰기 지연이 가능하며 트랜잭션 커밋하기 전까지 SQL을 바로 보내지 않고 모아서 보낼 수 있습니다.
4. 변경 감지(Dirty checking): 스냅샷을 1차 캐시에 들어온 데이터를 찍습니다. commit 되는 시점에 Entity와 스냅샷과 비교하여 update SQL을 생성합니다.
5. 지연 로딩: 엔티티에서 해당 엔티티를 불러올 때 그 때 SQL을 날려 해당 데이터를 가져옵니다.

JPA와 JPQL은 무슨 관계?

JPQL: Java Persistence Query Language의 약자로, DB 테이블이 아닌 엔티티의 객체를 대상으로 검색하는 객체 지향 쿼리입니다.
JPA: JPQL을 읽고 분석해서 SQL을 생성한 후 DB에 SQL을 실행하는 일을 합니다.
JPA는 특정 DB에 의존하지 않아 여러 DB에도 동일한 JPQL을 사용하면 DB에 접근할 수 있습니다. (Dialect - 방언만 변경하면 JPQL 수정 없이 DB 변경 가능)

=> 정리) JPA를 사용하기 위해 Repository 인터페이스를 만들고, JpaRepository를 상속받습니다.
여기에서 정의한 인터페이스 메서드를 실행하여 DB 연동을 하는데요.
이때, JPA는 인터페이스 메서드 이름을 분석해서 JPQL로 변환하고, 이를 가지고 SQL을 만들어서 DB에 SQL을 실행하는 과정을 합니다.

JPA Propagation 전파단계를 설명

JPA Propagation : 트랜잭션 동작 도중 다른 트랜잭션을 호출(실행)하는 상황에 선택할 수 있는 옵션

JPA를 쓴다면 그 이유에 대해서 설명

  • JPA를 사용하는 이유는 객체지향 프레임워크이기 때문입니다. JPA를 사용하면 비즈니스 로직이 RDBMS에 의존하는 것이 아니라, 자바 코드로 표현될 수 있기 때문입니다. 그로 인해서 생산성이 높아진다고 볼 수 있습니다.
  • JPA는 JPQL로 SQL을 추상화하기 때문에 RDBMS Vendor에 관계없이 동일한 쿼리를 작성해서 같은 동작을 기대할 수 있다는 장점도 가지고 있습니다. => 이는 database dialect를 지원하기 때문에 가지는 장점.

N + 1 문제는 무엇이고 이것이 발생하는 이유와 이를 해결하는 방법

N+1문제: 하나의 쿼리를 실행할 때 추가로 N개의 쿼리가 실행되는 문제
즉시 로딩과 지연 로딩 전략 각각의 상황에서 발생할 수 있다.

즉시 로딩에서 발생하는 이유? : JPQL을 사용하는 경우 전체 조회를 했을 때, 영속성 컨텍스트가 아닌 데이터베이스에서 직접 데이터를 조회한 다음 즉시로딩 전략이 동작하기 때문
지연 로딩에서 발생하는 이유? : 지연로딩 전략을 사용한 하위 엔티티를 로드할 때, JPA에서 프록시 엔티티를 unproxy 할 때 해당 엔티티를 조회하기 위한 추가적인 쿼리가 실행되어 발생

해결 방법
1. FetchJoin 사용하는 방법 : JPQL의 join fetch를 사용. JPQL에서 성능 개선 및 최적화를 위해 제공하는 기능으로 연관된 엔티티나 컬렉션을 함께 한 번에 조회하는 역할을 한다. (Inner Join)
(일반 조인은 패치 조인과는 다르게 오직 지정된 SELECT 결과만 가져올 수 있고, 연관 엔티티나 컬렉션을 함께 가져오지 못합니다.)

  • FetchJoin 단점?
  1. 번거롭게 쿼리문을 작성해야 함
  2. JPA가 제공하는 Paging API 사용 불가능 (Pageable 사용 불가)
  3. 한 엔티티 안에 일대다관계 컬렉션이 두 개 이상인 경우 사용 불가
  4. 패치 조인 대상에게 별칭을 부여할 수 없음

2. @EntityGraph를 사용하는 방법 : @EntityGraph의 attributePaths에 같이 조회할 연관 엔티티명을 적으면 됩니다. ,(콤마)를 통해 여러 개를 줄 수도 있습니다.(Outer join)

  1. @Fetch(FetchMode.SUBSELECT)를 사용하는 방법
  2. @BatchSize를 사용해 조절하거나 전역적인 batch-size를 설정하는 방법

Fetch Join과 EntityGraph 사용 시 주의할 점이 있나?

FetchJoin과 EntityGraph는 공통적으로 카테시안 곱(Cartesian Product) 이 발생 하여 중복이 생길 수 있습니다.

Q. 카테시안 곱이란? : 두 테이블 사이에 유효 join 조건을 적지 않았을 때 해당 테이블에 대한 모든 데이터를 전부 결합하여 테이블에 존재하는 행 갯수를 곱한만큼의 결과 값이 반환되는 것

해결 방법?
1. JPQL에 DISTINCT 를 추가하여 중복 제거
2. OneToMany 필드 타입Set으로 선언하여 중복 제거

즉시 로딩(Eager Loading)과 지연 로딩(Lazy Loading)의 차이점

즉시 로딩 (Eager Loading): 연관된 엔티티를 즉시 조회하는 방식

  • @ManyToOne(fetch = FetchType.EAGER)
    • 장점: 조회 시 즉시 사용할 수 있음
    • 단점: 불필요한 데이터 로딩으로 성능 저하 가능

지연 로딩 (Lazy Loading): 실제로 접근할 때만 데이터를 조회하는 방식 (권장)

  • @OneToMany(fetch = FetchType.LAZY)
    • 장점: 필요할 때만 로딩하여 성능 최적화 가능
    • 단점: LazyInitializationException 발생 가능 (영속성 컨텍스트가 닫히면 연관 데이터 조회 불가)

JPA와 트랜잭션- JPA에서 트랜잭션이 필요한 이유

  • JPA는 트랜잭션 단위로 데이터 변경을 관리하기 때문
    - @Transactional이 없으면 flush()가 자동 호출되지 않아 변경 사항이 DB에 반영되지 않을 수 있음

Q. @Transactional의 주요 특징은?
1. 읽기 전용 트랜잭션 (readOnly = true)

  • 조회 성능 최적화 가능 (쓰기 지연 SQL 비활성화)
@Transactional(readOnly = true)
public List<User> getUsers() { ... }

동작방식

  • readOnly = false일 경우, 트랜잭션이 커밋될 때 변경된 엔티티를 자동으로 flush()
  • readOnly = true일 경우, Hibernate 내부에서 flush()를 비활성화하여 변경 사항이 DB에 반영되지 않음

장점
1. 불필요한 flush() 호출 제거
• 변경 감지(Dirty Checking) 수행 X
• SQL UPDATE 또는 INSERT 쿼리 실행 방지
2. JDBC Connection 최적화
• Connection.setReadOnly(true) 설정으로 DB의 성능 최적화
• 일부 데이터베이스(MySQL, PostgreSQL 등)에서는 읽기 전용 트랜잭션이 더 빠르게 동작
3. 트랜잭션 격리 수준 최적화
• SET TRANSACTION READ ONLY; 설정으로 데이터 무결성 보호
• 쓰기 작업이 차단되어 성능 부담 감소

2. 트랜잭션 롤백 (rollbackFor = Exception.class)

  • 예외 발생 시 자동 롤백 가능
@Transactional(rollbackFor = Exception.class)
public void updateUser() { ... }

JPA 캐싱 - JPA의 1차 캐시와 2차 캐시 차이점?

1차 캐시(First-Level Cache)란?

  • EntityManager(영속성 컨텍스트) 단위에서 관리되는 기본적인 캐시
  • 같은 EntityManager 내에서 동일한 엔티티를 조회하면 DB를 조회하지 않고 메모리에서 가져옴
  • 트랜잭션이 종료되면 EntityManager가 종료되므로 1차 캐시는 사라짐

2차 캐시 (Second-Level Cache)란?

  • 애플리케이션 전체에서 공유되는 캐시
  • EntityManagerFactory 단위에서 관리됨 (서버가 종료될 때까지 유지)
  • DB 조회 비용을 줄이기 위해 JPA가 지원하는 추가적인 캐시 메커니즘
  • 2차 캐시는 JPA 자체적으로 제공하지 않고, 캐시 라이브러리를 별도로 설정해야 함
  • 1차 캐시와 다르게 여러 EntityManager 간에 공유 가능

1. 1차 캐시 (기본 제공)
• EntityManager 단위에서 관리 (세션 범위)
• 동일한 트랜잭션 내에서 같은 엔티티를 조회하면 캐시에서 반환됨
2. 2차 캐시 (옵션, 설정 필요)
• 애플리케이션 전역에서 엔티티를 캐싱하는 기능
• ehcache, Hazelcast 등의 구현체를 사용하여 캐싱 가능

profile
🇬🇧영국대학교)Computer Science학과 졸업 📚Data, AI, Backend 분야에 관심이 많습니다. 👉Email: kimbg9876@gmail.com

0개의 댓글