JPA

[JPA] 영속성 컨텍스트

경딩 2024. 11. 16. 01:09

 

jpa 란?

 

JPA 저장

멤버객체를 만든다고 가정해보자

멤버 객체를 회원 DAO 에 넘기고 회원 DAO 가 JPA 에게 멤버 회원 객체를 저장해줘 라고 던지기만 하면 JPA 가 자동으로 JPA 가 회원 객체를 분석하고 자동으로 INSERT SQL 을 만들어줘도 JDBC API 를 사용해서 db 에 insert 쿼리를 날려준다.

또한 패러다임의 불일치도 해결해준다.

자바 컬렉션의 저장하듯 한줄의 코드로 JPA 에게 회원을 저장시킬 수 있따.

 

이떄 회원가 같은 객체를 JPA 에서 엔티티라 부른다. 

엔티티란? DB 테이블에 대응하는 하나의 클래스라 생각하면 된다.

 

 

JPA 조회

 

조회또한 마찬가지로 JPA 가 다 알아서 해준다. EnityObject 를 잘 만들어서 결과로 돌려준다.

 

jpa 에서 가장 중요한 두가지가 있다.

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

영속성은 JPA 를 이해하는 가장 중요한 용어이다.

"엔티티를 영구 저장하는 환경" 이라는 뜻이다.

 

 

엔티티 매니저?

영속성 컨텍스트는 논리적인 개념으로 눈에 보이지 않는다.

엔티티 매니저를 통해서 영속성 컨텍스트에 접근한다.

EntityManager.persist(entity);

 

 

 

 

// 객체를 생성한 상태(비영속)

Member member = new Member();

member.setId("member1");

member.setUsername("회원1");

 

// 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");

 

 

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        // 엔티티 매니저는 데이터 변경 시 트랜잭션을 시작해야한다.
        tx.begin();
        // 객체를 생성한 상태(비영속)
        Member member = new Member();
        member.setId("member1");
        member.setUsername("회원1");
        
        // 객체를 저장한 상태(영속)
        em.persist(member);

 

 

1차 캐시 조회

find 문 조회시 1차 캐시에서 우선 조회 후 있을 경우 해당 캐시의 엔티티를 반환하고 없을 경우 DB 에서 조회하여 1차캐시에 저장 후 캐시의 엔티티 값을 반환한다.

            Member member = new Member();
            member.setId("member1");
            member.setName("회원1");
            //1차 캐시에 저장됨
            em.persist(member);
            //1차 캐시에서 조회
            Member findMember = em.find(Member.class, "member1");
            // db 에서 조회 : select 문 날라감
            Member findMember2 = em.find(Member.class, "member2");

영속 엔티티의 동일성 보장

Member a = em.find(Member.class, "member1");  
Member b = em.find(Member.class, "member1");
 System.out.println(a == b); //동일성 비교 true
  • 1차 캐시로 반복 가능한 읽기(REPEATABLE READ) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 애플리케이션 차원에서 제공

 

 

엔티티 등록

트랜잭션을 지원하는 쓰기 지연

 

  • JPA 는 persist 문장 실행시 바로 db 에 insert 문을 실행하는 것이 아닌 트랜잭션은 커밋하는 순간에 db 에 insert 문을 실행한다.

 

EntityManager em = emf.createEntityManager();
 EntityTransaction transaction = em.getTransaction();
 //엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
 transaction.begin();  // [트랜잭션] 시작
 
em.persist(memberA);
em.persist(memberB);
 //여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
 
 
 //커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
 transaction.commit(); // [트랜잭션] 커밋

  • persist 시 쓰기 지연 SQl 저장소에 insert 문을 보관하였다가 transaction.commit() 시 jpa 에서 flush 가 동작하면서 실제로 insert 문이 실행된 후 실제 db commit 이 실행됩니다.

 

 

엔티티 수정

변경감지

 

  • 커밋을 하면 내부적으로 flush 가 호출된다. 그 이후 엔티티와 스냅샷을 비교한다.
  • 1차 캐시 내부에는 pk 인 id , 와 엔티티, 스냅샷이 존재한다.
  • 스냅샷은 db 에서 읽어온 값이든 내가 집어넣은 값이든 최초의 상태를 스냅샷으로 찍어둔다.
  • 즉 최초로 영속성 컨텍스트에 들어온 상태를 스냅샷으로 찍어둔다.

커밋 순간 플러시가 되면서 jpa 는 엔티티와 스냅샷을 일일히 다 비교후 값이 다른 부분을 update 쿼리로 생성하여 쓰기 지연 sql 에 저장해둔다.

그리고 쓰기 지연 저장소에서 최종적으로 업데이트가 된다.

 

 

플러시란? 

영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 것을 말한다.

즉 영속성 컨텍스트의 있는 쿼리들을 db 에 실행하는 것이다.

 

데이터베이스 트랜잭션이 커밋되면 플러시가 자동으로 발생한다.

플러시 발생시

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

 

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

em.flush() - 직접 호출 // 거의 쓸일이 없지만 테스트 시 필요

트랜잭션 커밋 - 플러시 자동 호출

JPQL 쿼리 실행 - 플러시 자동 호출

'JPA' 카테고리의 다른 글

공통 인터페이스 기능  (1) 2024.12.07
양방향 연관관계와 연관관계 주인  (0) 2024.12.05