JPA - 영속성 컨텍스트2

지환·2024년 5월 4일

JPA

목록 보기
5/5
post-thumbnail

출처 | 나무소리

영속성 컨텍스트 - 동작방식

  • 영속성 컨텍스트는 EntityManager 단위로 관리된다.

  • EntityManager.persist() : 를 통한 영속객체 등록은 우선 해당 객체가 1차 캐시에 저장되고 일반적으로
    ----> 트랜잭션이 커밋되는 시점에 Insert 쿼리가 데이터베이스에 반영된다.

  • EntityManager.find() : 를 통한 데이터 검색은 -> 우선 1차 캐시를 통해 해당 객체를 검사
    • 없을 경우 select 쿼리를 통해 데이터베이스에서 검색을 수행

영속성 컨텍스트

  • 영속 컨텍스트를 통해 관리되는 영속객체는 --> 객체의 상태 변경에 따라 Update 쿼리가 생성되고, "커밋 시점에" 데이터베이스에 반영된다.
  • 객체의 변경 사항은 1차 캐시의 스냅샷(snapshot) 정보를 통해 판별

  • 영속 객체의 상태가 변경되면, 1차 캐시의 스냅샷과 비교하고 다를 경우, Update 쿼리를 생성 SQL 저장소에 저장한다.

flush

  • 플러시(flush)는 영속성 컨텍스트의 내용을 데이터베이스와 동기화 하는 것을 의미

  • 플러시 3가지 방식

    • EntityManager.flush() 직접 호출을 통한 플러시
    • 트랜잭션의 커밋을 통한 자동 플러시
    • JPQL 쿼리 실행을 통한 자동 플러시
  • 플러시를 실행한 이후에도 영속성 컨텍스트의 내용은 그대로 유지된다.

  • flush 했다고 해서 완전히 database에 반영된 것이 아니다. commit()을 해야 완전히 동기화 된 것이다.

Entity LifeCycle

  • "영속 객체"는 총 4가지로 구분된다.

    • 비영속(New) : 영속성 컨텍스트로 관리되기 이전 순수 객체 상태

    • 영속(Managed) : 영속성 컨텍스트로 등록되고 관리되는 상태

    • 준영속(Detached) : 영속성 컨텍스트의 관리에 있다가 분리된 상태(Managed -> Detached)

    • 삭제(Removed) : 영속 데이터의 삭제를 위한 상태(EntityManager.remove())


public class CustomerJpaExam {

    public static void main(String[] args) {

        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("customer-exam");
        EntityManager em = entityManagerFactory.createEntityManager();
        EntityTransaction et = em.getTransaction();

        et.begin();

        try{
            Customer customer = new Customer("ID0003", "Hong"); // 새로운 객체 생성 --> 비영속상태(new)
            em.persist(customer);// 비영속상태 -> "영속상태"(Managed)로 바꾸는 과정


            em.flush(); // 이렇게 flush를 진행하면 데이터베이스와 동기화가 된다. 지금은 commit을 진행하지 않았다.
            // 여기서 실행을 하게 되면 persist에 대한 Insert쿼리가 전송된다.


        }
        catch (Exception e)
        {
            et.rollback();
        }
        finally {
            em.close();
        }
        entityManagerFactory.close();


    }
}
  

  • em.persist(): 이렇게 flush를 진행하면 데이터베이스와 동기화가 된다. 지금은 commit을 진행하지 않았다.

    • 여기서 실행을 하게 되면 persist에 대한 Insert쿼리가 전송된다.
  • commit() : 진행하면 flush()가 자동으로 실행된다.

  • flush()를 진행하고 실질적인 데이터베이스에선 커밋이 일어나지 않았기 때문에, 반영되지 않았다.
public class CustomerJpaExam {

    public static void main(String[] args) {

        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("customer-exam");
        EntityManager em = entityManagerFactory.createEntityManager();
        EntityTransaction et = em.getTransaction();

        et.begin();

        try{
            Customer customer = new Customer("ID0005", "Hong"); // 새로운 객체 생성 --> 비영속상태(new)
            em.persist(customer);// 비영속상태 -> "영속상태"(Managed)로 바꾸는 과정


            em.flush();
            // 이렇게 flush를 진행하면 데이터베이스와 동기화가 된다. 지금은 commit을 진행하지 않았다.
            // 여기서 실행을 하게 되면 persist에 대한 Insert쿼리가 전송된다.
            // 데이터베이스에 commit이 진행되지 않았음
            Query query = em.createQuery("SELECT c FROM Customer c", Customer.class);
            List<Customer> customers = query.getResultList();
            System.out.println(customers);



        }
        catch (Exception e)
        {
            et.rollback();
        }
        finally {
            em.close();
        }
        entityManagerFactory.close();


    }


flush를 사용하지 않는다면?

  • commit() 시에 flush() 된다.
 try{
            Customer customer = new Customer("ID0005", "Hong"); // 새로운 객체 생성 --> 비영속상태(new)
            em.persist(customer);// 비영속상태 -> "영속상태"(Managed)로 바꾸는 과정


           // em.flush();
            // 이렇게 flush를 진행하면 데이터베이스와 동기화가 된다. 지금은 commit을 진행하지 않았다.
            // 여기서 실행을 하게 되면 persist에 대한 Insert쿼리가 전송된다.
            // 데이터베이스에 commit이 진행되지 않았음
            Query query = em.createQuery("SELECT c FROM Customer c", Customer.class);
            List<Customer> customers = query.getResultList();
            System.out.println(customers);

            et.commit();

        }
  • 커밋을 진행하면 디비에 어떻게 반영되는지 살펴보자.



public class CustomerJpaExam {

    public static void main(String[] args) {

        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("customer-exam");
        EntityManager em = entityManagerFactory.createEntityManager();
        EntityTransaction et = em.getTransaction();

        et.begin();

        try{
            Customer customer = new Customer("ID0005", "Hong"); // 새로운 객체 생성 --> 비영속상태(new)
            em.persist(customer);// 비영속상태 -> "영속상태"(Managed)로 바꾸는 과정

            Customer foundCustomer = em.find(Customer.class,"ID0005"); // 여기선 영속상태로 1차캐시에 들어가있기 때문에, SELECT 쿼리를 보내지 않는다.
            et.commit();

        }
        catch (Exception e)
        {
            et.rollback();
        }
        finally {
            em.close();
        }
        entityManagerFactory.close();


    }

  • 가운데 em.detach(customer);를 삽입한다면?

    • select를 발생시킨다.
  • 이전 코드에서 ID0005를 넣어놨기 때문에 -> 영속상태로 만들어놨기 때문에

  • em.detach(customer)로 설정하여 준영속상태로 변경했음

profile
아는만큼보인다.

0개의 댓글