JpaRepository 인터페이스만 상속받아도 다양한 편의 기능을 제공한다. 항상 당연하게 써왔지만 문득 엔티티 매니저의 주입 시점이 궁금하여 관련 강의를 보면서 구현체를 살펴봤다.
SimpleJpaRepository가 바로 JpaRepository의 구현체이다. 메서드 내부는 대부분 JPA의 기본 기능을 활용하여 구현되어 있었고, 눈여겨볼 만한 몇가지를 정리했다.
생성자
- JpaEntityInformation, EntityManager를 생성자를 통해 주입받는다
클래스 어노테이션
@Repository
- 스프링 빈으로 등록된다(컴포넌트 스캔의 대상이 된다)
- 스프링은 JPA, JDBC 등 데이터 접근 계층에 대한 여러 예외를 추상화하여 일관된 예외 계층을 제공하는데, 이러한 장점을 취할 수 있다
@Transactional(readOnly = true)
- 스프링 데이터 JPA의 모든 기능은 트랜잭션을 걸고 시작한다
- readOnly = true 옵션을 사용하여 약간의 성능향상을 얻는다(자바 ORM 표준 JPA 프로그래밍 p.682 참조)
- 다만 save, deleteById 등 변경 기능을 수행하는 메서드는 특수하게 메서드 레벨에서 @Transactional이 붙어있다
- JPA의 모든 데이터 변경은 트랜잭션 안에서 일어나야 하는데, 스프링 데이터 JPA는 이를 기본적으로 제공한다고 할 수 있다
- 이러한 이유로 서비스 레벨에서 트랜잭션이 걸려있지 않아도 데이터 등록, 변경이 가능하다(트랜잭션이 레포지토리 계층에 걸려있다)
메서드
save
- 새로운 엔티티면 저장(persist)
- 새로운 엔티티가 아니면 병합(merge)
- 이는 추가적인 SELECT가 발생하므로 준영속 상태에 있는 엔티티를 save하지 않도록 주의해야 한다
- 수정이 필요할 때 변경감지를 활용하자
- 새로운 엔티티를 판단하는 전략
- 식별자가 참조 타입일 때 null인지 여부로 판단
- 식별자가 기본 타입일 때 '0'인지 여부로 판단
- Persistable 인터페이스를 구현하여 판단 로직 변경 가능(isNew 메서드 오버라이딩)
saveAll
- save를 반복해서 호출한다, 즉 배치성 쿼리가 아니다
- 스프링 데이터 JPA 배치 Insert와 관련해서 좋은 글이 있어 링크를 남긴다
deleteById & delete
- deleteById는 먼저 findById를 수행하고 해당 엔티티가 존재하지 않는다면 예외를 던진다
- delete는 비영속상태거나 존재하지 않는다면 바로 메서드를 빠져나온다
- save와 유사하게 merge를 사용하므로 사용에 주의해야 한다
참고
'JPA' 카테고리의 다른 글
[JPA] 실무에서 만난 N+1 문제 해결하기 (feat. LazyInitializationException) (1) | 2023.10.25 |
---|---|
[JPA] StoredProcedureQuery execute와 executeUpdate 차이 및 사용법 (0) | 2022.11.23 |
[JPA] 스프링 데이터 JPA에서 조인 컬럼(FK)을 조건으로 쿼리 메서드 만들 때 주의사항 (0) | 2022.07.22 |