Search
Duplicate
📒

[스프링 JPA] 05. 스프링 데이터 JPA 분석

상태
완료
수업
JPA
주제
JPA
4 more properties
참고

스프링 데이터 JPA 구현체 분석

NOTE
스프링 데이터 JPA가 제공하는 공통 인터페이스의 구현체

SimpleJpaRepository

NOTE
@Repository @Transactional(readOnly = true) public class SimpleJpaRepository<T, ID> ...{ @Transactional public <S extends T> S save(S entity) { if (entityInformation.isNew(entity)) { em.persist(entity); return entity; } else { return em.merge(entity); } } ... }
Java
복사

@Repository

JPA예외를 스프링이 추상화한 예외로 변환해준다.

@Transactional

JPA의 모든 변경은 트랜잭션 안에서 동작한다.
서비스 계층에서 트랜잭션 시작 → 리포지토리에서 트랜잭션 시작
서비스 계층에서 트랜잭션 시작 → 리포지토리는 해당 트랜잭션을 전파받아서 사용
SimpleJpaRepository에 구현된 메서드들이 이미 트랜잭션 안에서 처리되도록 구성되었기 때문에 트랜잭션이 없어도 데이터를 등록, 변경이 가능했음!

@Transactional(readOnly = true)

데이터를 단순히 조회만 할 때 readOnly = true 옵션을 사용하면 약간의 성능향상 있음
flush()를 할 필요가 없기 때문!

save()

새로운 엔티티 → 저장(persist())
새로운 엔티티 → 병합(merge())

새로운 엔티티를 구별하는 방법

NOTE
@Transactional public <S extends T> S save(S entity) { if (entityInformation.isNew(entity)) { em.persist(entity); return entity; } else { return em.merge(entity); } }
Java
복사
어떻게 JPA는 새로운 엔티티인지 판단하는가?

새로운 엔티티를 판단하는 기본 전략

NOTE
식별자가 객체 일 떄
null인지 아닌지로 판단
식별자가 자바 기본 타입일 때
0인지 아닌지로 판단
Persistable 인터페이스를 구현해서 판단 로직을 변경할 수 있음

Persistable 구현

NOTE
@Entity @EntityListeners(AuditingEntityListener.class) @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Item implements Persistable<String> { @Id private String id; @CreatedDate private LocalDateTime createdDate; public Item(String id) { this.id = id; } @Override public String getId() { return id; } @Override public boolean isNew() { return createdDate == null; } }
Java
복사
isNew()함수가 새로운 엔티티인지 판단
[ 참고]
JPA 식별자 생선전략이 @GenerateValue인 경우 save() 호출 시점에 식별자가 없기 때문에 새로운 엔티티로 인식해서 정상동작
하지만 JPA 식별자 생성 전략이 @ID만 사용하는 경우, 식별자 값이 있는 상태로 save()가 호출되서 save()에서 새로운 엔티티가 아니라 판단해서 merge()를 호출한다.
merge()는 우선 DB를 호출해서 값을 확인하고, 없다면 새로운 엔티티를 호출할 뿐 아니라, 모든 값을 교체해버리기 떄문에 사이드이펙트가 발생할 수 있다.
따라서 Persistable을 사용해서 새로운 엔티티 확인 여부를 직접 구현하는것이 가장 좋다!