안녕하세요 오늘은 영속성, 다음글에선 영속성 전이에 대해서 파헤쳐보겠습니다.
기본적으로 Spring Data Jpa가 너무 잘 만들어져 편하게 사용하는 이 시점에 개념에 대해 확인하고 양질의 서비스를 만들어나가기 위해서 한번 영속성에 대해서 정리를 하고 넘어가려 합니다.
영속성
영속성 컨텍스트
→ JPA가 엔티티를 저장 및 관리하는 환경을 의미합니다. 어플리케이션과 DB 사이에서 객체를 관리하는 가상의 데이터베이스 환경입니다.
Entity 생명주기
1. 비영속
- 단순하게 객체를 새로 생성한 상태
- 영속성 컨텍스트로부터 아직 관리되지 않은 상태
2. 영속
- 영속성 컨텍스트로부터 관리되는 상태
- 식별자(PK)가 존재하는 상태
3. 준영속
- 영속성 컨텍스트로부터 관리되었었지만 관리가 종료된 상태
4. 삭제
- 엔티티가 삭제된 상태
그렇다면 영속성 상태는 코드로는 정확히 어떤 상태인지 확인해보겠습니다.
entityManager.persist(..)
기본적으로 persist(entity)를 통해서 영속성 컨텍스트에 엔티티 객체를 저장함으로써 영속성 상태를 만듭니다.
대부분의 개발자는 Spring Data Jpa를 주로 사용하기 때문에 주로 어떤 코드에서 영속성 상태를 만들 수 있는지 확인해보겠습니다.
.save(..)
.find..(..)
Spring Data Jpa를 사용할 때에는 저장 및 조회를 할 때 영속성 컨텍스트에 저장됩니다.
이는 기본적으로 JpaRepository를 상속하여 사용하기 때문입니다.
하지만 내부적으로 어떠한 로직이 있기에 영속성 컨텍스트를 통해 관리하는지 알아보겠습니다.
JpaRepository의 save와 find를 확인해보면 다음과 같습니다.
@Transactional
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null");
if (this.entityInformation.isNew(entity)) {
this.entityManager.persist(entity);
return entity;
} else {
return (S)this.entityManager.merge(entity);
}
}
역시나 저장 로직에는 기본적으로 persist를 통해서 영속성 컨텍스트에 저장합니다.
그렇다면 find 로직 중 가장 기본적인 findById를 확인해보겠습니다.
public Optional<T> findById(ID id) {
Assert.notNull(id, "The given id must not be null");
Class<T> domainType = this.getDomainClass();
if (this.metadata == null) {
return Optional.ofNullable(this.entityManager.find(domainType, id));
} else {
LockModeType type = this.metadata.getLockModeType();
Map<String, Object> hints = this.getHints();
return Optional.ofNullable(type == null ? this.entityManager.find(domainType, id, hints) : this.entityManager.find(domainType, id, type, hints));
}
}
persist가 어디에도 보이지 않습니다.
this.entityManager 를 사용하는 로직은 find를 통해 조회하는 로직 뿐입니다.
find를 확인해보겠습니다.
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockModeType, Map<String, Object> properties) {
this.checkOpen();
LockOptions lockOptions = null;
Object var26;
try {
if (lockModeType != null) {
this.checkTransactionNeededForLock(lockModeType);
lockOptions = this.buildLockOptions(lockModeType, properties);
}
EffectiveEntityGraph effectiveEntityGraph = this.loadQueryInfluencers.getEffectiveEntityGraph();
effectiveEntityGraph.applyConfiguredGraph(properties);
this.loadQueryInfluencers.setReadOnly(getReadOnlyHint(properties));
if (effectiveEntityGraph.getSemantic() == GraphSemantic.FETCH) {
this.setEnforcingFetchGraph(true);
}
var26 = this.byId(entityClass).with(this.determineAppropriateLocalCacheMode(properties)).with(lockOptions).load(primaryKey);
return (T)var26;
}
...
// 코드 양이 많아 일부만 들고 왔습니다.
아니 여기도 persist가 없는데 영속성 상태인게 맞아요? 라는 말이 나올 수도 있습니다.
영속 상태란 위에 적었던 것 처럼 영속성 컨텍스트로부터 관리하는 상태입니다.
- entityManager.persist(..) 를 통해서 영속성 컨텍스트에 직접 저장한 상태
- entityManager.find(..) 를 통해서 조회할시 DB에 존재한다면 조회 성공 후 영속성 컨텍스트에서 관리 상태
따라서 find를 해서 찾은 객체 또한 영속성을 가지게 되는 것이라고 할 수 있습니다.
이를 구분하여 혼동하지 않고 사용해야 할 것 같습니다.
준영속 상태는 어떻게 만들까요?
영속 상태에서 더 이상 관리하지 않는 상태라고 하였는데 이는 entityManager를 통해서 다음과 같이 작성합니다.
- entityManager.detach( .. ) 엔티티 영속 -> 준영속 상태 직접 변경
- entityManager.close() 종료
- entityManager.clear() 초기화
다음 글은 영속성 전이를 정리해보도록 하겠습니다.
'SpringBoot' 카테고리의 다른 글
SpringBoot 대용량 데이터 조회 (Index) (1) | 2025.07.03 |
---|---|
AOP 탐구 (0) | 2025.07.01 |
SpringEvent / EDA (2) | 2025.06.24 |
Spring 예외처리 (@ExceptionHandler, @ControllerAdvice) (0) | 2025.05.12 |
Spring Security 없이 로그인을 하는 방법 (Session) (0) | 2025.05.07 |