본문 바로가기
Programming/JPA & Spring Data JPA 기초

02. 코드 구조 & 영속 컨텍스트

by JKROH 2023. 2. 20.
반응형
해당 강의는 코드 위주로 진행됩니다. 실질적인 객체 처리를 담당하는 코드는 링크에서 확인하시길 바랍니다.

* 영속 단위 기준으로 초기화

public class UserSaveMain {
    public static void main(String[] args) {
        /*
        * EntityManagerFactory는 영속 단위 기준으로 생성한다.
        * persistence.xml의 persistence-unit name = "jpabegin" 에서 확인할 수 있듯 jpabegin을 식별자로 사용한다.
        * 식별자가 영속 단위를 구분하는 이름으로 사용된다.
        * 해당 이름으로 EnitityManagerFactory를 생성한다.
        * EnitityManagerFactory는 커넥션풀 등 DB연동에 있어 필요한 자원을 생성하는 작업을 한다.
        * Application을 처음 구동할 때 한 번만 EntityManagerFactory를 생성한다.
        */
        EntityManagerFactory emf =
                Persistence.createEntityManagerFactory("jpabegin");

        EntityManager entityManager = emf.createEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        try {
            transaction.begin();
            User user = new User("user@user.com", "user", LocalDateTime.now());
            entityManager.persist(user);
            transaction.commit();
        } catch (Exception ex) {
            ex.printStackTrace();
            transaction.rollback();
        } finally {
        /*
        * Application을 사용하고 종료할 때 EntityManagerFactory의 close()메소드를 사용해 팩토리를 닫는다.
        * 이 때 사용한 자원들을 반환한다.
        */
            entityManager.close();
        }

        emf.close();
    }
}

 

* EntityManager로 DB 연동

  • EntityManager가 JPA의 핵심 역할을 한다.
  • EntityManager로 DB 연동에 대한 모든 것을 처리한다.
        EntityManager entityManager = emf.createEntityManager(); // EntityManagerFactory를 통해 entityManager 생성한다.
        
        EntityTransaction transaction = entityManager.getTransaction(); // 생성, 삭제, 변경 등 트랜잭션이 필요한 작업을 수행하기 위해 EntityTransaction을 구한다.
        
        try {
            transaction.begin(); // 트랜잭션을 시작한다.
            
            ...entityManager를 통한 DB 작업
            
            transaction.commit(); // DB 작업이 끝나면 트랜잭션을 커밋한다.
        } catch (Exception ex) {
            transaction.rollback(); // 오류가 발생하면 트랜잭션을 롤백한다.
        } finally {
            entityManager.close(); // 트랜잭션 성공, 실패, 예외 발생 여부와 관계없이 EntityManager를 닫아준다.
        }

 

* 저장과 쿼리 실행 시점

transaction.begin();
User user = new User("user@user.com", "user", LocalDateTime.now());
entityManager.persist(user);
logger.info("EntityManager.persist 호출함");
transaction.commit();
logger.info("EntityTransaction.commit 호출함");
더보기

 실제 insert 쿼리는 언제 실행될까?

INFO jpabasic.reserve.domain.UserSaveMain - EntityManager.persist 호출함
DEBUG org.hibernate.SQL - insert into user (craete_date, anme, email) value (?, ?, ?)
INFO jpabasic.reserve.domain.UserSaveMain - EntityTransaction.commit 호출함
더보기

 persist메소드를 호출할 때 insert쿼리가 실행된다고 알기 쉽지만, 실제로는 commit시점에 insert쿼리를 실행한다.

식별자를 생성하는 형식에 따라 persist 시점에 insert를 실행하기도 하지만, 식별자를 직접 설정하는 경우에는 commit 시점에 실행된다.

 

* 수정과 쿼리 시점

  • 수정은 트랜잭션 범위 내에서 객체를 변경하면 자동으로 된다.
            transaction.begin();
            User user = entityManager.find(User.class, "user@user.com");
            if (user == null) {
                System.out.println("User 없음");
            } else {
                String newName = "이름" + (System.currentTimeMillis() % 100);
                user.changeName(newName);
                logger.info("User.changeName 호출함");
            }
            transaction.commit();
            logger.info("EntityTransaction.commit 호출함");
더보기

 마찬가지로 실제 update 쿼리는 언제 실행될까?

DEBUG org.hibernate.SQL - select문 실행
INFO j.reserve.domain.UserUpdateMain - User.changeName 호출함
DEBUG org.hibernate.SQL - update user set create_date=?, name=?, where email=?
INFO j.reserve.domain.UserUpdateMain - EntityTransaction.commit 호출함
더보기

  find()로 찾을 때 select가 실행되고 changeName()과 commit() 사이에서 update가 실행된다. 즉, chageName()으로 인해 변경된 데이터를 저장하고 있다가 트랜잭션이 commit() 되는 시점에 변경된 객체를 찾아서 update 쿼리를 실행하는 것이다.

 

* 영속 컨텍스트(PERSISTENCE CONTEXT)

  • 영속 컨텍스트는 DB에서 읽어온 객체나, 응용 프로그램에서 EntityManager를 통해 생성 / 읽어온 객체를 저장하고 있는 일종의 메모리 공간이다.
  • 영속 객체를 보관하고 있다가 commit 하는 시점에 context에 있는 객체와 실제 프로그램에서 사용한 객체 간의 변경이 발생했는지 확인하고 변경이 발생하면 그 내역을 commit하는 시점에 DB에 반영한다.
  • 따라서 위의 예시에서 persist로 객체를 저장한 것이나 changeName으로 변경한 객체가 DB에 바로 저장되는 것이 아니라 영속 컨텍스트에 보관이 되고 commit 시점에 변경 쿼리를 실행해 DB에 반영된다.

* 정리

- 기본 구조

  • Application이 구동될 때 EntityManagerFactory 초기화, Application이 종료될 때 close 한다.
  • DB 작업이 필요할 때마다
    • EntityManager 생성
    • EntityManager로 DB 조작
    • EntityTransaction으로 트랜잭션 관리
  • 스프링과 연동할 때는 대부분의 작업을 스프링이 대신 처리하므로 매핑 설정 중심으로 작업한다.

- 영속 컨텍스트

  • 엔티티를 메모리에 보관한다.
  • 변경을 추적해서 트랜잭션 커밋 시점에 DB에 반영한다.
반응형

'Programming > JPA & Spring Data JPA 기초' 카테고리의 다른 글

05. 엔티티 식별자 생성 방식  (0) 2023.02.23
04. 엔티티 매핑 설정  (0) 2023.02.22
03. 엔티티 단위 CRUD 처리  (0) 2023.02.21
01. 일단 해보기  (0) 2023.02.20
00. 들어가며  (0) 2023.02.17

댓글