1일차에서 더티 체킹을 공부하며 영속 상태만 되니, 비영속, 준영속은 영속성 컨텍스트가 관리하지 않아서 더티 체킹이 안된다느니... 실제로 JPA에서 가장 중요한 개념 중 하나가 영속성 컨텍스트라고 생각한다. 그렇게 배웠다.
영속성 컨텍스트를 공부하기에 앞서 영속 상태가 뭔지, 엔티티 객체가 JPA 코드로 어떻게 관리되는지 라이프싸이클을 알아보자.
위 사진이 엔티티 객체의 라이프싸이클을 모두 담고 있다.
하나하나 알아볼 것이다. @Transactional을 사용하면 자동으로 엔티티의 생명주기가 돌아가기 때문에 EntityManager를 활용할 것이다.
객체가 생성되어 메모리에 올라갔지만, 영속성 컨텍스트랑 상관이 없는 상태다.
persist() 메서드를 통해 영속상태로 만들어줄 수 있다.
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myEntityObjectTest");
EntityManager em = entityManagerFactory.createEntityManager();
// 비영속 상태
Book book = new Book();
book.setName("1번책");
book.setContent("1번책 내용");
객체를 생성하고, 값을 세팅한 상태다. 아직 엔티티 매니저랑은 상관이 없다.
어? 1일차에서 저렇게만 해도 더티체킹이 된다고...?
- @Transactional은 자동으로 비영속 / 영속 / 준영속 / 제거 상태로 만든다. 현재 EntityManager를 사용하기 때문에 영속상태가 되려면 메서드를 불러와야 한다.
엔티티 매니저에 의해 영속성 컨텍스트에 관리되고 있는 상태
엔티티 매니저를 사용하여 엔티티를 조회하거나 저장하면, 해당 엔티티는 자동으로 관리 상태로 전환
persist()메서드를 사용하여 영속 상태로 만들 수 있다.
remove(), detach() 등 메서드로 삭제, 준영속 상태로 만들 수 있다.
영속 상태를 비영속 상태로는 만들 수 없다.
// 트랜잭션 시작
EntityTransaction transaction = em.getTransaction();
transaction.begin();
try {
// 영속 상태
em.persist(book);
// 커밋
transaction.commit();
} catch (Exception e) {
if (transaction.isActive()) {
transaction.rollback();
}
간단하게 생성한 객체를 persist()함수의 인자로 넣어 영속 상태로 만들 수 있다.
find()를 통해서 찾았다면 그 역시 영속 상태로 관리한다.
영속성 컨텍스트에서 저장되었다가 분리된 상태
비영속 상태와 유사하지만 가장 다른점은 영속성 컨텍스트 식별자 유무다. 영속성 컨텍스트에서 관리된 적있는 준영속 상태는 식별자가 존재한다.
close(), clear(), detach() 함수로 준영속상태로 만들 수 있다. 각각 역할이 다르다.
close()는 영속성 컨텍스트 종료 메서드다. 종료 후 영속 상태 객체들은 당연히 분리된다.
clear()은 영속성 컨텍스트에서 관리하는 객체를 모두 제거하여 준영속 상태로 만든다.
detach()는 특정 엔티티를 영속성 컨텍스트에서 분리하는 메서드다.
finally {
// 준영속 상태
em.detach(book);
}
clear(), close()를 사용해도 준영속 상태로 만들 수 있다.
굳이 사용해본 적 없다. 개발자가 준영속 상태를 명시하는 일이 적다고 한다.
https://stackoverflow.com/questions/31446/detach-an-entity-from-jpa-ejb3-persistence-context
book.setContent("사실 2번책임");
em.merge(book);
준영속이 왜 필요한지 궁금해서 찾아봤다. 명확한 답변은 얻기 힘들었다.
https://stackoverflow.com/questions/21622841/why-need-detached-entities-in-jpa
궁금한 사람이 나뿐은 아니었나보다.
원래는 1차 캐시에 너무 많은 데이터가 입력되면 OutOfMemoryException이 나기 때문에, clear(), evict(지금의 detach())를 사용하여 관리하려고 만들었다.
그럼 굳이 식별자를 안 가져도 되는 거 아닌가
굳이 준영속 상태를 사용하는 이유를 찾아봤는데
DB와 영속성 컨텍스트에서 해당 엔티티를 삭제한다.
영속 상태일때만 가능하다.
em.remove(book);
엔티티 객체는 비영속 -> 영속 -> 준영속 or 삭제 순서대로 생명주기가 존재한다.
@Transactional을 사용한다면 Spring-data-Jpa가 알아서 관리해주지만, 그래도 잘 사용하기 위해서 알아두는 편이 좋다.
다음은 영속성 컨텍스트다. 뭔가 거슬러 가는 느낌이긴하다.
근데 진짜 준영속 상태가 왜 필요한가요?
항해 개발자 취업 리부트 코스를 수강하고 작성한 콘텐츠 입니다.