영속성 컨텍스트(Entity LifeCycle)

이종윤·2022년 2월 12일
0

Spring JPA

목록 보기
15/23

😎 영속성컨텍스트에서 가장 주체가 되는 클래스는 엔티티메니져객체이다. 엔티티는 하나의 객체이기 때문에 엔티티와 DB레코드 사이에 어떻게 연결해주고, 어떻게 반영해 주는지, 모두 엔티티메니져의 역활이다. 영속성컨텍스트 내에서 엔티티매니져가 엔티티의 상태를 어떻게 변화시키는지 알아보자.

Entity 생애주기 알아보기(Entity LifeCycle)

  • 엔티티 라이프사이클 이라고 하면 4가지의 상태가 존재한다.
    - 비영속상태 : new OR Transient 상태
    • 영속상태 : managed 상태
    • 준영속상태 : deteched 상태
    • 삭제상태 : removed 상태

😁비영속 상태 (Transient 상태)

  • 영속성 컨텍스트가 해당 영속성객체를 관리하고 있지 않는 상태이다. 그 필드는 영속화에대해서 제외하겠다 라는 말이다.
  • 똑같이 Transient 상태라고도 하며, New 상태라고도 한다.
  • 사실 이 상태는 엔티티라기 보다 단순하나의 자바 object로 분류된다.
@Service
public class UserService {
    @Transactional
    public void put(){
        User user = new User();
        user.setName("newUser");
        user.setEmail("newUser@fast.com");
    }
}
  • 위 코드에서 User객체는 비영속상태이다.
@SpringBootTest
class UserServiceTest {
    @Autowired
    private UserService userService;

    @Autowired
    private UserRepository userRepository;

    @Test
    void test() {
        userService.put();
        System.out.println(">>>>>> " + userRepository.findByEmail("newUser@fast.com"));
    }
}
Hibernate: 
    select
        user0_.id as id1_7_,
        user0_.created_at as created_2_7_,
        user0_.updated_at as updated_3_7_,
        user0_.email as email4_7_,
        user0_.gender as gender5_7_,
        user0_.name as name6_7_ 
    from
        user user0_ 
    where
        user0_.email=?
>>>>>> null
  • select쿼리가 작동은 하지만 실제 DB의 user는 아직 없다는걸 확인할 수 있다.
  • DB와 연결이 된게 아니라 단순히 자바 객체로만 존재하다가 Transactio이 종료되고나면 쓸모가 없어져서 영속화 되지 않고 가비지 컬랙터를 통해서 사라지는 데이터가 된다.

😮영속 상태 (managed 상태)

  • 해당 엔티티가 영속성컨텍스트의 관리하에 있다는 뜻이다.
  • 영속성 컨텍스트에서 관리한다는 뜻은 객체의 변화를 별도로 처리하지 않아도 DB에 반영시킨다.
    @Transactional
    public void put(){
        User user = new User();
        user.setName("newUser");
        user.setEmail("newUser@fast.com");

        userRepository.save(user);
    }
  • 🤚 참고로 save메서드를 써도 영속상태로 관리하게된다. 이유는 SimpleJpaRepository클래스에서 정의해놓은 save메서드를 보면 EntityManager에 Persist, 즉 입력하기 때문이다.
  • 하지만 영속화에 대해 디테일하게 보기 위해 EntityManager를 직접 호출해 주자.
@Service
@RequiredArgsConstructor
public class UserService {

    private final EntityManager entityManager;

    private final UserRepository userRepository;


    @Transactional
    public void put() {
        User user = new User();
        user.setName("newUser");
        user.setEmail("newUser@fast.com");

//        userRepository.save(user);
        entityManager.persist(user);
        
        user.setName("newUserAfterPersist");    //persist 한 다음에 실행한 쿼리도 flush된다.
    }
}
insert 
    into
        user
        (created_at, updated_at, email, gender, name) 
    values
        (?, ?, ?, ?, ?)
        
        ...
        ...
        ...
>>>>>> User(super=BaseEntity(createdAt=null, updatedAt=null), id=6, name=newUser, email=newUser@fast.com, gender=null)
        
  • insert 쿼리가 작동하고, select가 실행되면서 DB에서 값을 불러올수 있다.
  • 영속성 컨텍스트가 해당 엔티티를 관리하는 상태가 되었다.
  • 영속화 해서 managed 상태로 바뀌면 어떤 변화가 일어날까?
    - 영속성 컨텍스트 내에서 관리되는 엔티티는 셋터를 통해 엔티티객체 정보가 변경되면, 별도로 save를 하지 않아도 DB 데이터와 정확성을 맞춰준다.
    • 영속화 되어있으면 save가 실행되지 않아도 트랜젝션이 끝나면 flush가 일어난다는 것.
    • 즉, 쿼리가 DB와 같아지는 시점은 함수를 호출했을때가 아니라 flush될때라는 점이 중요하다.
    • 여기서 setName이 persist이후에 들어갔지만 실행되는 경우가 영속성 컨텍스가 제공하는 더티 체크라고 한다.

Dirty Check

  • 영속성 컨텍스가 가지고있는 엔티티객체는 처음 컨텍스를 로드를 할때 객체를 일종의 스냅샷으로 가지고 있다. 변경내용을 DB에 적용하는 시점 (flush하는 시점)에 해당 스냅샷과 현재 엔티티값을 비교하여 변경 값이 발견되면 변경값도 적용시키는 쿼리를 때린다.

😊준영속 상태 (detached)

  • 원래 영속화 되었던 상태를 분리해서 영속성 컨텍스트 밖으로 꺼내는 상태
...
...
    @Transactional
    public void put() {
        User user = new User();
        user.setName("newUser");
        user.setEmail("newUser@fast.com");

//        userRepository.save(user);
        entityManager.persist(user);
        entityManager.detach(user); // 준 영속화


        user.setName("newUserAfterPersist");    //persist 한 다음에 실행한 쿼리도 flush된다.
        entityManager.merge(user); // 재 영속화
        
        entityManager.flush(); // clear하기 전에 flush()
        entityManager.clear(); // 변경 작업에 대한 것을 모두 clear한다.
    }
}
  • entityManager를 사용하는 이유는 다른 상태에 대한 메서드는 모두 springDataJpa에서 제공해준다. 하지만 detach는 따로 제공해주지 않기 때문이다. 일반적인 경우에서는 굳이 detach 하지않는다는 뜻 이다.
  • detached하면 영속성 컨텍스트에서 더이상 관리하지 않는다.
  • 준 영속상태의 엔티티라도 명시적으로 다시 entityManager의 merge메서드를 호출하면 영속성 컨텍스트에서 관리한다.
  • clear를 써도 detach와 비슷한 효과를 보지만 변경 작업에 대한 모든 것을 clear하기 때문에 clear하기 전에 flush() 해주는것이 좋다.

삭제상테(removed상태)

  • 삭제 상태는 딱히 특별한 것은 없고 해당 엔티티는 더 이상 사용하지 못하는 상태가 된다.
        User user1 = userRepository.findById(1L).get();
        entityManager.remove(user1);
    @Test
    void test() {
        userService.put();
//        System.out.println(">>>>>> " + userRepository.findByEmail("newUser@fast.com"));
        userRepository.findAll().forEach(System.out::println);
    }
profile
OK가자

0개의 댓글