본문 바로가기
Java & Kotlin/Spring

Spring JPA

by kiwi_wiki 2025. 1. 12.

JPA

자바 ORM 기술 표준으로 객체와 관계형 데이터베이스를 매핑하는 기술

  • ORM (객체-관계 매핑)
    • 자바 객체와 데이터베이스 테이블을 자동으로 매핑
    • @Entity, @Table 등의 어노테이션을 통한 매핑 설정
  • 쿼리 메서드
    • 메서드 이름으로 쿼리 자동 생성
    • 복잡한 쿼리는 @Query 어노테이션으로 처리
  • 지연 로딩(Lazy Loading)
    • 연관된 엔티티를 실제 사용하는 시점에 로딩
    • 프록시 객체를 통한 성능 최적화
    • 지연 로딩과 즉시 로딩
      • @ManyToOne, @OneToMany 등의 관계 설정
      • 성능 최적화를 위한 로딩 전략 선택

영속성 컨텍스트

엔티티의 CRUD를 담당하면서 저장했거나 불러온 엔티티를 기억하는 1차 캐시 역할을 한다.

  • 1차 캐시
    • 영속성 컨텍스트 내부에 엔티티를 보관
    • 동일 트랜잭션 내에서 반복 조회 시 DB 접근 없이 캐시에서 조회
  • 동일성 보장
    • 같은 엔티티를 반복 조회해도 동일한 객체 참조 반환
    • 트랜잭션 범위의 repeatable read 보장
  • 변경 감지(Dirty Checking)

 

  • 엔티티의 변경사항을 자동으로 감지
    flush 발생 시 entity와 스냅샷을 비교한다. 스냅샷은 처음 db에서 읽어왔을 때의 내용
  • 바뀐 내용이 있으면 쓰기 지연 SQL 저장소에서 update 쿼리를 작성하여 트랜잭션 커밋 시점에 변경된 엔티티를 DB에 자동 반영
  •  
  • 쓰기 지연
    • 쓰기 지연 SQL 저장소가 존재
    • entity 분석 후 insert 쿼리를 생성하고 쓰기 지연 SQL 저장소에 쌓은 뒤 commit 하는 순간 쿼리들이 flush 되면서 DB로 날아감
  • flush 하는 방법
    • em.flush()
    • 트랜잭션 commit 시 자동 호출
    • JPQL 쿼리 실행 시 자동 호출
  • 엔티티의 생명 주기

 

  • 비영속(new/transient): 영속성 컨텍스트와 관련 없는 상태
  • 영속(managed): 영속성 컨텍스트에서 관리되는 상태
  • 준영속(detached): 영속성 컨텍스트에서 분리된 상태.
    • detach(entity): 엔티티를 영속성 컨텍스트에서 분리
    • clear(): 영속성 컨텍스트를 비움
    • close(): 영속성 컨텍스트를 종료
  • 삭제(removed): 영속성 컨텍스트와 DB에서 삭제되도록 예약된 상태. 최종적으로 모두 삭제된다
준영속과 비영속의 차이점
비영속 상태는 식별자가 있을 수도 없을 수도 있지만 준영속 상태의 경우 식별자가 반드시 존재한다.
- 비영속 상태에서는 entity 객체 생성 시 id를 초기화하지 않았으므로 식별자가 없다.
- 만약 개발자가 초기 entity객체 생성 시 직접 id를 초기화해 생성하면 EntityManage는 비영속이 아닌 준영속 상태로 간주한다.
- 즉 준영속 상태는 내부 HashMap에 같은 식별자를 갖는 Entity 가 존재하지 않지만, Entity 에는 식별자가 있는 모든 경우를 의미한다.
- 이런 경우 비영속임에도 불구하고 persist 뿐만 아니라 merge 메서드도 가능하다

장점

  • 생산성 향상: SQL 쿼리 작성 최소화
  • 유지보수성: 객체지향적인 코드 작성 가능
  • 데이터베이스 독립성: 다양한 DB 벤더 지원

복잡한 쿼리나 성능이 중요한 경우에는 네이티브 SQL이나 QueryDSL를 함께 사용하는 것이 좋음

트러블 슈팅

  • N+1 쿼리 문제: 한 번의 조회로 가져온 엔티티 컬렉션에서 지연 로딩으로 관련 엔티티를 반복적으로 조회할 때 발생
    • 해결 방법
      • @EntityGraph 사용
      • fetch join을 활용한 JPQL 사용
      • @BatchSize 설정으로 in 쿼리 사용
  • 성능 문제
    • 비효율적 쿼리 생성: JPA가 쿼리를 생성하므로 항상 최적화된 쿼리는 아님
    • 대량 데이터 처리 시 메모리 초과
      • JPQL UPDATE, DELETE 문 사용
      • EntityManager.clear()로 캐시 관리
    • Lazy Loading, Eager Loading으로 인한 문제: 로딩 방법을 잘못 사용하면 성능 문제가 야기될 수 있음
  • Dirty Checking: 과도한 변경 감지로 불필요한 업데이트가 발생할 수 있음. 필요한 부분만 수정하거나 변경 감지를 비활성화

JPA vs MyBatis

JPA MyBatis
ORM 기반 SQL 매핑 프레임워크 기반
객체 지향적 접근
자동화된 SQL 생성
변경 감지
직접적인 SQL 제어
복잡한 쿼리 작성이 유연
복잡한 쿼리에서 제한적일 수 있음 더 많은 매핑 코드 작성 필요
객체 지향적인 설계가 중요한 프로젝트일 때 사용 데이터베이스 중심 설계나 복잡한 쿼리 사용이 필요한 경우 사용

 

728x90
반응형

'Java & Kotlin > Spring' 카테고리의 다른 글

Spring @Transaction  (0) 2025.01.14
Spring Filter & Interceptor  (0) 2025.01.13
Spring Boot AutoConfiguration  (0) 2025.01.11
Spring Framework?  (0) 2025.01.10