[JPA] JPA 개요 - 영속성 컨텍스트와 엔티티 생명주기

dooboocookie·2022년 10월 26일
0

엔티티 매니저

엔티티

  • JPA는 테이블엔티티를 매핑하고. 이 엔티티를 저장, 수정, 삭제 조회하는 일을 한다.

엔티티 매니저 팩토리

	(출처 : 자바 ORM 표준 JPA 프로그래밍 - 김영한)
  • 엔티티 매니저 팩토리는 엔티티 매니저를 만들기 위해 DB당 하나씩 사용
    • 여러 쓰레드 동시 접근 가능 (엔티티 매니저는 아니다)
  • 메이븐 프로젝트의 경우, resources/META-INF/persistence.xml로 엔티티 매니저 팩토리 설정을 한다.
    • Gradle로 설정하는 SpringBoot프로젝트의 경우 application.properties나 .yaml에 설정할 수 있다.
<persistence version="2.2"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="이름 설정">
        <properties>
            <!-- jdbc driver -->
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <!-- 접근하려는 계정이나 DB-->
            <property name="javax.persistence.jdbc.user" value="계정명이나 DB명 입력"/>
            <!-- 접근하려는 계정의 비밀번호 -->
            <property name="javax.persistence.jdbc.password" value="비밀번호 입력"/>
            <!-- DB의 url -->
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
            <!-- DB별 방언 -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
        </properties>
    </persistence-unit>
</persistence>

hibernate.dialect(방언)은 DBMS별(오라클, MySQL, ...)별 그에 맞는 적절한 SQL문 등을 날릴 수 있도록 하는 설정이다.

  • 엔티티 매니저 팩토리 생성
    • 비용이 많이 든다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistenc-unit 이름");
  • 엔티티 매니저 팩토리 닫기
    • 애플리케이션이 종료될 때 닫아줘야 한다.
emf.close();

엔티티 매니저

  • 엔티티 매니저는 테이블과 매핑되어있는 엔티티를 관리(저장, 수정, 삭제, 조회)를 하는 역할을 한다.

    • 엔티티 매니저는 여러 쓰레드에서 동시에 접근하면 안된다.
    • 즉, 하나의 엔티티 매니저에 두 개 이상의 요청이 오면 안된다.
  • 엔티티 매니저 생성

    • 큰 비용이 들지 않는다.
EntityManager em = emf.createEntityManager();
  • 엔티티 매니저 닫기
    • 하나의 쓰레드가 끝나면, 닫아줘야 한다.
em.close();

엔티티 트랜잭션

  • JPA는 저장, 수정, 삭제하는 작업은 트랜잭션 안에서 해야한다.
  • 트랜잭션 생성
EntityTransaction tx = em.getTransaction();
  • 트랜잭션 (시작~커밋)
tx.begin();
//하나의 트랜잭션 단위의 작업들...
tx.commit();

영속성 컨텍스트

  • 마치 영속성 컨텍스트가 엔티티 매니저와 동일하다 생각할 수 있지만, 비슷(?)하지만 꼭 그렇진 않다.
  • 엔티티를 영속화 한다.
  • 엔티티 매니저를 통해, 엔티티를 영속성 컨텍스트에 저장한다(관리한다)

엔티티의 생명주기

	(출처 : 자바 ORM 표준 JPA 프로그래밍 - 김영한)
  1. 비영속 (New)
Member member = new Member();
member.setName("두부쿠키");
  • 엔티티로 매핑된 객체를 생성한 단계, 아직 영속성 컨텍스트에서 관리되거나 저장된 객체가 아니다.
  1. 영속 (Managed)
em.persist(member);
em.find(Member.class, 1L);
  • 엔티티 매니저를 이용해서 영속성 컨텍스트에 저장하거나(.persist()) 조회한(.find()) 엔티티
    • 영속 상태의 엔티티는 1차 캐시에 저장된다.
      • 밑에서 자세한 설명
  1. 준영속 (Removed)
  • 영속 상태의 엔티티를 영속성 컨텍스트가 관리하지 않도록 한 엔티티
em.detach(member);
em.clear();
em.close(); // 엔티티 매니저를 닫아도 모두 준영속 상태가 된다.(당연히)
  1. 삭제 (removed)
  • 영속 상태의 엔티티를 삭제한 것
    • DB에 DELETE문을 날린다.
em.remove(member);

1차 캐시

  • 영속 상태의 엔티티를 1차 캐시에 저장한다.
em.persist(member1);
  • 비영속 엔티티는 영속성 컨텍스트에 의해 관리되고 있지 않았으므로, 1차 캐시에는 없었다.
  • 영속화 하면서 1차 캐시에 저장된다.
    1차 캐시
    ID Entity
    1L Member1
em.find(Member.class, 2L);
  • DB에는 있지만 영속 상태는 아닌 엔티티를 find()해서 영속 상태로 만들면 1차 캐시에 저장된다.
    1차 캐시
    ID Entity
    1L Member1
    2L Member2
em.find(Member.class, 1L);
  • 이미 1차 캐시에 있는 엔티티를 조회하게 되면 SELECT문을 따로 날리지 않고 1차 캐시에서 엔티티를 가져온다.

  • 따라서, 동일한 영속성 컨텍스트 안에서 같은 ID를 갖는 엔티티는 동일한 객체이다.

Member memberA = em.find(Member.class, 1L);
Member memberB = em.find(Member.class, 2L);
System.out.print(memberA==memberB); //true

쓰기 지연

  • em.persist(member)를 호출하는 순간에는 1차 캐시에 저장이 되지 DB에 INSERT문을 그 동시에 날리는 것은 아니다.
tx.commit();
  • 이 트랜잭션 안에서 persist()에 의해서 영속 상태로 되어 1차 캐시 안에 저장된 엔티티들은 쓰기 지연 SQL 저장소에 INSERT문이 저장된다.
  • commit()과 동시에 flush되어, INSERT문들이 커밋 직전에 날라간다.

더티 체킹(변경감지)

  • 영속 상태의 엔티티는 필드(컬럼) 값을 바꿔 주면, 다른 작업을 하지 않아도 commit() 시, UPDATE문이 날라간다.
1차 캐시
ID Entity 스냅샷
1L Member1 Member1 스냅샷
2L Member2 Member2 스냅샷
  • 영속 상태로 관리될 최초의 스냅샷과, 현재의 엔티티의 변경사항을 감지하여 쓰기 지연 SQL 저장소에 저장하고,
  • commit() 시, flush된다.

flush

  • 쓰기 지연 SQL 저장소에 저장된 쿼리(등록, 수정, 삭제)를 DB에 전송하는 작업

유발 방법

  1. 직접적인 호출
em.flush();
  1. 커밋
tx.commit();
  1. JPQL 쿼리
em.createQuery("select ... from ...", Member.class);
  • flush는 쓰기 지연 SQL 저장소와 관련된 것이지, 영속성 컨텍스트를 비우지는 않는다.
  • 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 작업
profile
1일 1산책 1커밋

0개의 댓글