Entity LifeCycle

이담호·2024년 10월 18일
post-thumbnail

1. Entity LifeCycle

엔티티에는 4가지 상태가 존재한다.

  • 비영속(new/transient) = 영속성 컨텍스트와 전혀 관계가 없는 상태
  • 영속(managed) = 영속성 컨텍스트에 저장된 상태
  • 준영속(detached) = 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제(removed) = 삭제된 상태

1. 비영속

엔티티 객체를 생성하고 Entity Managerpersist() 메서드를 호출하지 않은 상태이다.

2. 영속

Entity Managerpersist() 메서드를 호출해 Entity 객체를 영속성 컨텍스트에 저장한 상태이다.

Entity 객체가 영속성 컨텍스트에 의해 관리되는 상태이다.

영속 상태가 된다고 바로 DB에 쿼리가 날라가지 않는다. (즉, DB 저장 X)

트랜잭션의 commit 시점에 영속성 컨텍스트에 있는 정보들이 DB에 쿼리로 날라간다.

// 객체를 생성한 상태 (비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();

// 객체를 저장한 상태 (영속)
entityManager.persist(member);
https://gmlwjd9405.github.io/2019/08/08/jpa-entity-lifecycle.html

3. 준영속

영속성 컨텍스트에 저장되었다가 분리된 상태와 영속성 컨텍스트에서 지운 상태이다.

// 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
entityManager.detach(member);

4. 삭제

엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제한다.

// 객체를 삭제한 상태(삭제)
em.remove(member);

2. 영속, 준영속 상태

영속 상태

  1. entityManager.persist()영속성 컨텍스트에 저장된 상태
  2. entityManager.find() 로 조회할 때 영속성 컨텍스트 1차 캐시에 없어서 DB에서 조회한 후 해당 Entity를 1차 캐시에 올라간 상태 (엔티티 매니저관리하는 상태)

준영속 상태

  1. 영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)된 상태
  2. 준영속 상태에서는 영속성 컨텍스트가 제공하는 기능을 사용하지 못한다.
    1. Dirty Checking, Update Query

3. 공부한 내용

JPA 는 기본적으로 한 요청 당, 하나의 Entity Manager 를 사용한다.

JpaRepository 의 구현체인 SimpleJpaRepository 는 EntityManager 를 필드로 가진며 생성자 주입받아 싱글톤으로 사용한다.

싱글톤임으로 동시성 문제가 발생할 수 있기 때문에 스프링 프레임워크는 여기에 실제 EntityManager를 주입하는 것이 아니라, 실제 EntityManager를 연결해주는 가짜 EntityManager를 주입해둔다(proxy).

그렇다면 동일한 EntityManager 에 여러 Thread 가 접근해도 괜찮을까?

괜찮다.

내가 정리한 내용)

  • JPA는 기본적으로 트랜잭션 단위영속성 컨텍스트가 부여되어 사용되고
  • 별도의 스레드는 결국 별도의 트랜잭션인 것임으로, 별도의 영속성 컨텍스트를 사용하게 된다.
  • 따라서 별도의 영속성 컨텍스트에서 각각 커넥션 풀을 사용하게 됨으로 동시성 문제에 안전하다.

gpt)

  • HTTP 요청은 스프링에서 별도의 스레드로 처리된다.
  • 스레드는 독립적인 트랜잭션을 관리하며, 각 트랜잭션은 자체적인 영속성 컨텍스트를 가진다.
  • 이를 통해 각각의 스레드가 자신만의 영속성 컨텍스트에서 데이터베이스 작업을 수행하게 된다.

@Transactional 을 Service 단에서 선언하지 않으면 각각 Repository 코드 내부에 존재하는 @Transactional 을 사용해 별도의 트랜잭션으로 동작한다.

만약 아래와 같은 코드를 실행하는데 하나의 트랜잭션으로 묶여있지 않다면

Member savedMember = memberRepository.save(member); // -> 트랜잭션 Tx1, 영속성 컨텍스트1
Member foundMember = memberRepository.findById(member.getId()).get();// -> 트랜잭션 Tx2, 영속성 컨텍스트2

두 객체를 비교할 시 다른 객체로 판별한다.


출처

https://gmlwjd9405.github.io/2019/08/08/jpa-entity-lifecycle.html

https://trillium.tistory.com/135

0개의 댓글