(JAVA) JPA 기초

정찬's avatar
Nov 26, 2024
(JAVA) JPA 기초
 

JPA와 Spring Data JPA의 차이

 
  • JPA
    • EntityManager를 직접 관리
    • EntityManager를 통해서 Entity CRUD
    • EntityTransaction 통해서 트랜잭션 직접 관리
  • Spring Data JPA
    • JpaRepository를 상속한 Repository 인터페이스로 Entity CRUD
      • EntityManager는 내부적으로 자동 구현된 코드에서 사용 됨
    • @Transactional 어노테이션 통해서 트랜잭션 자동 관리
      • Spring Boot에 의해 자동 생성된 PlatformTransactionManager에 의해 관리
 

PlatformTransactionManager란?

 
Spring 프레임워크에서 트랜잭션 관리를 위한 핵심 인터페이스이다.
어플리케이션의 데이터베이스 작업, 메시징 시스템, 기타 트랜잭션을 요구하는 작업들에 대해 일관된 트랜잭션 처리를 제공하며, 다양한 트랜잭션 전략을 추상화한다.
 

주요 특징

  1. 트랜잭션 추상화
    1. JDBC, JPA, JTA등 다양한 기술에 의존하지 않고 공통된 트랜잭션 관리 API를 제공한다.
    2. 하위 구현체에 따라 데이터베이스나 기술에 적합한 트랜잭션 전략을 사용할 수 있다.
  1. 프로그래밍 방식 지원
    1. 선언적 트랜잭션(@Transactional)과 프로그래밍 방식(직접 API 호출) 모두 지원한다.
  1. 트랜잭션 전파 및 격리 수준 제어
    1. 트랜잭션 전파 속성, 격리 수준, 타임아웃 등을 설정하여 세부적인 트랜잭션 제어가 가능하다.
 

사용 방법

 
  1. 선언적 트랜잭션 관리 (@Transactional)
@Service public class MyService { @Transactional public void performTransaction() { // 트랜잭션 처리 코드 } }
 
  1. 프로그래밍 방식 트랜잭션 관리
 
@Autowired private PlatformTransactionManager transactionManager; public void performTransaction() { TransactionDefinition def = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(def); try { // 트랜잭션 처리 코드 transactionManager.commit(status); // 성공 시 커밋 } catch (Exception e) { transactionManager.rollback(status); // 예외 발생 시 롤백 throw e; } }
 

@Repository vs Spring Data Repository

 

@Repository

  • 정의 : 데이터 접근 계층(DAO)를 나타내는 Spring 어노테이션
    • Spring Stereotype annotaion중 하나이다.
  • 역할
    • 예외 변환 : 데이터 접근 예외를 Spring의 DataAccessException으로 변환
    • 직접 데이터베이스 접근 로직 작성
  • 특징
    • 직접 구현 필요
    • 커스텀 쿼리, 복잡한 데이터 로직에 유용
    • 자동 CRUD 기능 제공하지 않음
 

Spring Data Repository

 
  • 정의 : Spring Data JPA에서 제공하는 데이터 접근 인터페이스
  • 역할
    • 자동으로 CURD 기능 제공
      • @EnableJpaRepositories 설정에 따라 Repository interface 자동 감지 및 동적으로 구현 생성해서 Bean으로 등록
    • 메소드 이름 기반 쿼리 자동 생성
    • 페이징, 정렬, 동적 쿼리, 커스텀 쿼리 지원(@Query 사용)
 

@Query

 
// JPQL 쿼리 (파라미터 바인딩 = 위치 기반) @Query("select i from Item i where i.price >= ?1") List<Item> findAllByPriceAtLeastByQuery(long price); // JPQL 쿼리 (파라미터 바인딩 = 이름 기반) @Query("select i from Item i where i.price >= :price") List<Item> findAllByPriceAtLeastByQueryParam(long price); // 네이티브 SQL 쿼리 (파라미터 바인딩 = 위치 기반) @Query(value = "select * from item where price >= ?1", nativeQuery = true) List<Item> findAllByPriceAtLeastByNativeQuery(long price); // 네이티브 SQL 쿼리 (파라미터 바인딩 = 이름 기반) @Query(value = "select * from item where price >= :price", nativeQuery = true) List<Item> findAllByPriceAtLeastByNativeQueryParam(long price);
 

@Modifying

 
@Query를 통해 insert, update, delete 쿼리를 수행할 경우 붙여줘야 한다.
영속성 컨텍스트를 거치지 않고 바로 DB에 반영되기 때문에 수정 후 바로 조회할 때 주의해야 한다.
clearAutomatically = true 옵션을 통해 자동으로 영속성 컨텍스트를 초기화할 수 있다.
 
@Modifying @Query("update Item i set i.name = :name where i.id = :id") int updateNameByIdByQuery(long id, String name); // `@Modifying` with `clearAutomatically` @Modifying(clearAutomatically = true) @Query("update Item i set i.name = :name where i.id = :id") int updateNameByIdByQueryAndClear(long id, String name);
Share article

lushlife99