[Spring Boot/JPA] 영속성 컨텍스트와 준영속 컨텍스트

2023. 5. 9. 14:32
반응형

영속성 컨텍스트

JPA에서 영속성 컨텍스트는 엔티티를 관리하는 논리적인 개념

영속성 컨텍스트는 어플리케이션과 DB사이에서 객체를 보관하는 가상의 DB같은 역할을 한다

엔티티를 메모리에 저장하고, 엔티티의 생명주기를 관리하며, 엔티티와 데이터베이스 간의 작업을 캐시해서 처리하는 작업을 수행한다.

 

 

Entity의 생명주기

 

1. 엔티티의 생명주기 관리

  • 새로운 엔티티를 생성할 때 EntityManager를 사용하여 영속성 컨텍스트에 저장
  • 영속 상태의 엔티티는 영속성 컨텍스트에 의해 관리되며, 변경 사항이 있으면 자동으로 감지하여 데이터베이스에 반영된다.
  • 엔티티를 삭제하면 영속성 컨텍스트에서 제거된다.
  • 의도적으로 영속성 컨텍스트에서 엔티티를 비영속 상태로 만들 수 있음

 

2. 엔티티와 데이터베이스 간의 작업을 캐시

  • 엔티티를 조회할 때, 영속성 컨텍스트에 조회할 내용이 있는지 확인하고, 있다면 데이터베이스를 조회하는 것 대신 캐시 데이터를 사용할 수 있음

 

3. 지연 로딩

  • 엔티티를 조회할 때, 연관된 엔티티를 즉시 로딩하는 것 대신, 필요할 때 로딩하는 지연 로딩을 지원한다.
  • 불필요한 데이터를 로딩하지 않아 최적화에 도움이 된다.

 

4. 영속성 컨텍스트의 범위는 트랜잭션 범위에서 수행됨

  • 영속성 컨텍스트의 범위는 트랜잭션 작업 범위에서 적용된다.
  • 트랜잭션이 커밋될 때 영속성 컨텍스트에서 변경된 엔티티를 데이터베이스에 Flush하게 된다.
  • 같은 트랜잭션 내에서, 같은 영속성 컨텍스트를 사용하여, 일관된 데이터를 유지한다.

비영속과 준영속

 

비영속

  • 엔티티 객체를 생성하였지만 아직 영속성 컨텍스트에 저장하지 않은 상태

준영속

  • 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 데이터베이스에서 조회한 엔티티 데이터를 사용하여 복사한 새로운 인스턴스도 준영속 상태에 속한다.
  • 영속 상태에서 준영속 상태로 분리시킬 때에는 em.detach()를 호출한다.

 


변경 감지와 병합(merge)

이전 포스팅에서 서비스에서 데이터를 수정할 때 Respository의 EntityManager의 merge()를 사용하여 업데이트시켰다. 해당 방법은 병합을 이용한 방법이었으며, 데이터베이스를 수정하기 위해 병합과 변경 감지의 방법에 대해 알아보겠다.

 

 

 


 병합

병합은 준영속 엔티티를 영속성 컨텍스트에 병합하는 방법을 의미한다.
준영속 엔티티의 ID(식별자)로 영속성 엔티티를 조회한 후, 영속 엔티티의 값을 준영속 엔티티의 값으로 교체한다.
트랜잭션이 커밋될 때 변경 감지 기능이 동작하여 데이터베이스에 Update되게 된다.

 

@Repository
@RequiredArgsConstructor
public class ItemRepository {
    private final EntityManager em;


    public void modify(Item item){
         em.merge(item); 
    }
}

 

병합을 사용하게 될 시 가장 큰 문제점은 준영속 엔티티의 속성(멤버변수)를 선택하여 반영할 수 없고 전체를 Update한다는 점이다.

따라서, 준영속 엔티티의 일부 멤버변수가 NULL이더라도 그대로 업데이트된다는 문제점이 있다.


변경 감지

 

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ItemService {
    private final ItemRepository itemRepository;



    @Transactional(isolation = Isolation.DEFAULT)
    public Item updateItem(Long itemId, String name, int price, int stockQuantity){
    
        //변경 감지를 이용한 아이템 수정
        Item findItem = itemRepository.findOne(itemId);
        findItem.setPrice(price);
        findItem.setName(name);
        findItem.setStockQuantity(stockQuantity);
        return findItem;

    }


}

변경 감지를 이용하는 방법은, 이미 영속성 컨텍스트에 있는 데이터를 조회하여, 수정하는 방법이다.

Setter를 통해 변경하게 되면, 해당 객체는 영속성 컨텍스트에서 관리되고 있으므로, 트랜잭션이 커밋될 때 변경된 내용이 반영되게 된다.

 

 

 

 


권장 사항

병합보다는 엔티티는 트랜잭션이 있는 서비스 계층에서 영속 상태의 엔티티를 조회하고, 데이터를 직접 변경하는 방법을 사용하자.

컨트롤러에서 엔티티를 생성하는 것은 지양하자.

트랜잭션이 있는 서비스 계층에 엔티티 식별자와 변경할 데이터를 정확하게 전달하자.

 
반응형

BELATED ARTICLES

more