Spring Data JPA - 3편
JpaRepository 분석하기
JpaRepository 를 까보면 구현체로 SimpleJpaRepository
를 사용한다.
- @Repository 를 적용해서 JPA 예외를 스프링이 추상화 한 예외로 변환한다.
- @Transactional 트랜잭션 적용
- JPA 의 모든 동작은 트랜잭션 안에서 동작
- 스프링 데이터 JPA 는 변경 (등록, 수정, 삭제) 메서드를 트랜잭션 처리
- 서비스 계층에서 트랜잭션을 시작하지 않으면 리파지토리에서 트랜잭션 시작
- 서비스 계층에서 트랜잭션을 시작하면 리파지토리는 해당 트랜잭션을 전파 받아서 사용
- 그래서 스프링 데이터 JPA 를 사용할 때 트랜잭션이 없어도 데이터 등록, 변경이 가능했던 것이다.
(사실은 트랜잭션이 리포지토리 계층에 걸려있는 것임)
save() 메서드
해당 내용은 중요하기 때문에 꼭 이해해두기!
- 새로운 엔티티면 저장 (persist)
- 새로운 엔티티가 아니면 병합 (merge)
entityInformation.isNew() 로 새로운 엔티티를 판단하는 기본 전략
- 식별자가 객체일 때
null
로 판단 - ex) Long 타입 - 식별자가 자바 기본 타입일 때
0
으로 판단 Persistable
인터페이스를 구현해서 판단 로직 변경 가능
위 내용을 잘 모르면 실무에서 이슈가 발생할 수 있다.
예를들어 아래와 같이 Item 엔티티를 만들어 둔다. (이때 @Id 는 @GeneratedValue 가 아님)
Item 엔티티를 save 할 때 문제가 발생한다.
PK 값이 넘어오기 때문에 isNew 메서드에서 false 가 발생하여 em.merge 를 해버리게 된다.
em.merge 는 실제 DB 에 값이 있다고 가정하기 때문에 select 쿼리를 날린다.
하지만 실제로는 값이 없으므로 insert 를 날려준다.
결과적으로 insert 는 되지만 불필요한 select 쿼리가 나가므로 비효율적이다.
PK 자동 생성(@GeneratedValue) 을 어쩔 수 없이 못쓰는 상황은 어떻하나요?
보통 대부분의 경우 자동 생성으로 엔티티를 생성하지만, 정말 어쩔 수 없이 못쓰는 상황이 있을 수 있다.
이때는 Persistable 을 사용해서 새로운 엔티티 확인 여부를 직접 구현하면 된다.
Persistable<식별자 타입> 을 implements 해주고getId()
, isNew()
를 구현해주면 된다.
보통 실무에서는 위와 같이 등록 시간 (@CreatedDate ) 을 조합해서 사용한다.
(@CreatedDate 에 값이 없으면 새로운 엔티티로 판단)
참고 : @CreatedDate 는 @EntityListeners 가 있어야 한다.
persist 가 되면 @CreatedDate 로 데이터가 들어간다.
Tip ) command + F12
단축키를 통해 해당 클래스 내 메서드를 쉽게 조회할 수 있다.
@Transactional(readOnly = true)
데이터를 단순히 조회만 하고 변경하지 않는 트랜잭션에서 해당 옵션을 사용하면 플러시를 생략
해서 약간의 성능 향상을 얻을 수 있다.
복잡한 통계성 쿼리는..
동적 쿼리를 편리하게 작성하기 위해 QueryDSL을 사용한다.
하지만 QueryDSL 도 결국은 JPQL 기반이라, 지원하지 않는 쿼리는
Spring JDBC Template 이나 Mybatis 등을 이용하여 쿼리를 짠다.
참고
- 실전! 스프링 데이터 JPA
'JPA' 카테고리의 다른 글
Querydsl - 2편 (0) | 2022.02.08 |
---|---|
Querydsl - 1편 (0) | 2022.02.08 |
JPA 를 공부하면서 알게 된 내용 정리 3 (0) | 2022.02.02 |
JPA 를 공부하면서 알게 된 내용 정리 2 (0) | 2022.01.29 |
JPA 를 공부하면서 알게 된 내용 정리 1 (0) | 2022.01.26 |
댓글