목차

    JPA에서 가장 중요한 2가지

    • 객체와 관계형 데이터 베이스 매핑하기 (Object Relational Mapping)
    • 영속성 컨텍스트

    영속성 컨텍스트

    • JPA를 이해하는데 가장 중요한 용어
    • "엔티티를 영구 저장하는 환경" 이라는 뜻
    • EntityManager.persist(entity);

    EntityManager.persist(entity)

    우리는 .persist를 해당 entity를 DB에 저장한다고 이해했다. 그렇지않고 우리는 entity를 DB에 저장하는 것이 아닌 영속성 컨텍스트에 저장하는 것이다.

    • 영속성 컨텍스트는 논리적인 개념이다.
    • 눈에 보이지 않는다.
    • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근

    영속성 컨텍스트 생성 과정

    EntityManasger를 생성하면 위 그림 처럼 영속성 컨텍스트가 생성됩니다.

    엔티티의 생성주기

    • 비영속(new/transient)
      • 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
    • 영속(managed)
      • 영속성 컨텍스트에 관리되는 상태
    • 준영속(detached)
      • 영속성 컨텍스트에 저장되었다가 분리된 상태
    • 삭제(removed)
      • 삭제된 상태

    비영속 상태(JPA랑 전혀 관계 없는 상태)

    영속

    DB에는 언제 저장하는가?

    em.persist(member);

    위의 상태에서는 DB에 저장한 것이 아닌 영속성 컨텍스트에 저장한 것이다. 그렇다면 언제 DB에 저장하는 것 인가?

    확인 코드 

    System.out.print("=== before ===");
    em.persist(member);
    System.out.print("=== after ===");

    결과 : before와 after사이에 insert문이 날라가지 않는다.

    이유

    tx.commit;

    트랜잭션 커밋 상태에서 결국 query가 날라가게 된다.

    준영속, 삭제

    회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태

    em.detach(member);

    객체를 삭제한 상태

    em.remove(member);

    영속성 컨텍스트의 이점

    바로 db에 저장하지 않고 중간과정을 거친다. 그래서 얻는 것은 다음과 같다.

    • 1차 캐시
    • 동일성 보장
    • 트랜잭션을 지원하는 쓰기 지연
    • 변경 감지
    • 지연 로딩

    엔티티 조회, 1차 캐시

    1차 캐시로 저장하고 db에 저장한다.

    어느 시점에? 트랜잭션

     데이터베이스에서 조회

    단, 한 트랜잭션안에서만 동작하기 때문에 큰 이점은 없다. 즉, 트랜잭션이 끝나면 휘발성으로 날라간다. 우리가 아는 캐싱을 적용하려면 2차캐싱을 적용해야한다. 

    영속 엔티티의 동일성 보장

    1차 캐시로 반복 가능한 읽기(Repeatable read) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공

    엔티티 등록 트랜잭션을 지원하는 쓰기 지연

    1차 캐시에 저장과 동시에 INSERT SQL 생성하여 쓰기 지연 SQL 저장소에 저장한다.

    그리고 transactio.commit();을 만나면 flush가 되면서 db에 날라가고 commit이 된다.

    • jpa batch 라는 것으로 size를 관리한다.
    • 약간 bulk insert 같은 느낌으로 버퍼를 모으는 느낌

    ★엔티티 수정 변경 감지(Drity Checking)★

    ​EntityManager em = emf.createENtityManager();
    EntityTransaction tr = em.getTransaction();
    tr.begin(); //트랜잭션 시작
    
    //영속 엔티티 조회
    Member memberA = em.find(Member.class, "memberA");
    //영속 엔티티 데이터 수정
    MemberA.setUserName("hi");
    MemberA.setAge(10);
    
    //em.update(member) 이런 코드가 있어야 하지 않을까?
    tr.commit(); //트랜잭션 커밋

    위의 코드를 보면 memberA라는 객체에 setName, setAge를 해주고 update 쿼리를 해주지 않았는데도 자동으로 update가 된다. 왜그럴까? 뭔가 set을 해주고 persist를 해줘야 반영이 될 것 같은데 말이다.

    1차 캐시안에는 @Id, Entity, 스냅샷이라는 것이 있다. 스냅샷은 최초로 영속성 컨텍스트에 들어온 값을 임시 저장하는 것이다. 그러고 Entity(새로 들어온 값) 스냅샷과 변경이 감지되면 update 쿼리를 쓰기 지연 SQL 저장소에 저장해버리고 DB에 반영한다.

    플러시

    영속성 컨텍스트의 변경내용을 데이터베이스에 반영

    플러시 발생

    • 변경 감지
    • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
    • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송
      • 등록, 수정, 삭제 쿼리

    영속성 컨텍스트를 플러시 하는 방법

    • em.flush() - 직접 호출 트랜잭션 커밋 전에 강제 느낌 (거의 사용x)
    • 트랜잭션 커밋 - 플러시 자동 호출
    • JPQL 쿼리 실행 - 플러시 자동 호출
    em.persist(memberA); 
    em.persist(memberB); 
    em.persist(memberC);
    // 중간에 JPQL 실행 
    query = em.createQuery("select m from Member m", member.class);
    List<Member> members = query.getResultList();
    • em.persist의 memberA,B,C는 아직 데이터베이스에 Insert 전이다.
    • 따라서 select 문에서 조회가 안될 것 같지만, JPQL은 flush가 자동으로 된다. 그래서 조회가 된다.
      • flush 여부 설정 가능
        • FlushModeType.AUTO... or COMMIT

    준영속 상태

    • 영속 -> 준영속
    • 영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)
    • 영속성 컨텍스트가 제공하는 기능을 사용 못함
    • 거의 비영속 상태에 가깝다.
      영속성 컨텍스트가 관리하지 않으므로 1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩을 포함한 영속성 컨텍스트가 제공하는 어떤한 기능도 동작하지 않는다.
    • 식별자 값을 가지고 있다.
      비영속 상태는 식별자 값이 없을 수도 있지만 준영속 상태는 이미 한 번 영속상태였으므로 반드시 식별자 값을 가지고 있다
    • 지연 로딩을 할 수 없다.
    //1 : 떼어내기
    em.detach(member); 
    tx.commit();//commit을 해도 em은 반영되지 않는다.
    
    //2 1차 캐시를 조회함 그래서 같은 내용 또 조회해도 select 쿼리가 또 나감
    em.clear();
    
    //3. em.close() : 종료

     

    'Back-end > JPA' 카테고리의 다른 글

    연관관계 매핑 기초  (0) 2022.08.22
    엔티티 매핑  (0) 2022.08.06
    [JPA] Batch Insert  (0) 2022.05.05
    JPA 소개  (0) 2022.03.14
    자바 ORM 표준 JPA 프로그래밍  (0) 2022.03.14

    + Recent posts