1. persist 와 merge
save
: 엔티티를 새로 저장하거나 변경 사항을 업데이트 한다.
persist
: 새로운 엔티티 객체를 영속성 컨텍스트에 추가한다.
merge
: 준영속 상태(detached)의 엔티티 객체를 받아 영속 상태로 전환한다.
여기서 준영속 상태는 엔티티가 현재 세션의 영속성 컨텍스트에 속하지 않는 상태를 의미한다.
즉, 데이터베이스에는 존재하지만 현재 세션에서는 관리되지 않는 상태이다.
2. Spring Data JPA에서의 동작 방식
Entity ID(식별자) 생성 전략
1) @GenerateValue
: 호출 시점에 식별자가 없으므로 새로운 엔티티로 인식해서 persist가 정상 동작한다.
2) 직접할당
: 이미 식별자 값이 있는 상태로, merge가 호출된다.
DB에 select 쿼리를 호출해서 엔티티가 있는지 확인한다.
만약 존재하면 DB 정보를 기반으로 새로운 영속 상태의 엔티티를 생성하고, 준영속 상태의 엔티티의 상태를 복사한다.
만약 존재하지 않는다면 새로운 엔티티로 취급하여 영속성 컨텍스트에 추가한다.
그리고 트랜잭션이 커밋될 때 insert 쿼리를 통해 DB에 반영된다.
이 때 직접할당의 경우에는 merge가 호출됨으로써
새로운 엔티티임을 인식하지 못하고, insert 쿼리 전에 select 쿼리를 1번 호출하게 된다.
따라서 Persistable를 사용해서 새로운 엔티티 확인 여부를 직접 구현하는 것이 좋다!!
cf. 등록시간(@CreatedDate)을 조합해서, 이 필드로 새로운 엔티티 여부를 확인하면 편리하다.
@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;
}
}
[JpaRepository save 구현체]
@Transactional
@Override
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null");
if (entityInformation.isNew(entity)) {
entityManager.persist(entity);
return entity;
} else {
return entityManager.merge(entity);
}
}
'Spring > Spring Data Jpa' 카테고리의 다른 글
7. Projections (0) | 2024.04.13 |
---|---|
5. 확장 기능 (0) | 2024.04.11 |
4. 쿼리 메소드 기능 (0) | 2024.03.25 |
3. 공통 인터페이스 기능 (1) | 2024.03.24 |
2. 예제 도메인 모델 (1) | 2024.03.23 |