영속성 관리

twocowsong·2023년 4월 26일
0

김영한_jpa

목록 보기
4/13
post-custom-banner

JPA에서 가장 중요한 2가지

  1. 객체와 관계형 DB매핑하기
  2. 영속성 컨텍스트 - 실제 JPA가 실행되는 원리

엔티티 매니저 팩토리와 엔티티 매니저


그림과 같이 사용자의 요청이 들어오게되면 매니저 팩토리에서 사용하기 위한 엔티티 매니저를 생성하여 사용합니다.


엔티티매니저를 생성하게되면, 영속성 컨텍스트가 생성됩니다.


엔티티 생명주기


엔티티는 위와같은 상태가 존재하는데 아래와 같이 코드에 따라 생명주기가 바뀌게됩니다.

	// 객체를 생성한 상태(비영속)
    Member member = new Member();
    member.setId("member1");
	member.setUsername("회원1");
	
    EntityManager em = emf.createEntityManager();
    em.getTransaction().begin();
    
    // 객체를 저장한 상태(영속)
    em.persist(member);
    
    // 회원 엔티티를 영속성 컨텍스트에서 분리(준영속)
    em.detach(member);
    
    // 객체를 삭제한 상태
    em.remove(member);


영속성 컨텍스트는 애플리케이션과 DB사이에 존재하는것으로, 이런 매커니즘에서 얻을수있는게 되게 많습니다.


1차 캐시


@ID가 key이며 Entity가 Value일경우 DB에 접근없이 캐쉬에서 member1의 정보를 조회할 수 있습니다.

허나 위처럼 member2처럼 캐쉬에 데이터가 없는경우 DB에 조회후 member2의 정보를 얻고 난 후 캐시에 저장합니다.

// INSERT START
Member member = new Member();
member.setId(101L);
member.setName("Hello JPA");
em.persist(member);

// SELECT
Member findMember = em.find(Member.class, 101L);
System.out.println("find Member ID = " + findMember.getId());
System.out.println("find Member NAME = " + findMember.getName());

INSERT 후 SELECT가 실행되는 코드입니다.


하지만 SELECT문이 로그에는 출력되지 않는걸 확인할수있습니다. 1차캐시(영속성 컨텍스트)에 데이터가 있기때문에 DB에서 조회하지않습니다.


쓰기지연 SQL 저장소

EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작

em.persist(memberA); // 1차 캐시에 저장 INSERT SQL 생성(쓰기 지연 SQL저장소에 저장)
em.persist(memberB); // 1차 캐시에 저장 INSERT SQL 생성(쓰기 지연 SQL저장소에 저장)

//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); 
// [트랜잭션] 커밋 -> 쓰기지연 SQL저장소에서 flush(쓰기) 되면서 DB에 저장됨
// 후 실제DB에 커밋이 됨.

버퍼링에 모아서 한번에 쓰게되어 이러한 이점들을 얻을수 있게되며 persistence.xml파일에 버퍼의 갯수를 설정하여 사용이 가능합니다.


엔티티 수정 변경 감지

	Member member = em.find(Member.class, 150L);
	member.setName("ZZZZZ");


위처럼 setName으로 member객체의 값 변경 시 UPDATE 쿼리가 실행된는걸 확인 할 수 있습니다.
별도에 업데이트 함수호출없이 set로 인하여 DB가 업데이트 되는 상황입니다.


1. commit 시 flush가 호출됩니다.
2. 1차 캐시에 @id, Entity 뿐만아니라 스냅샷이라는 정보도 저장됩니다.
스냅샵은 값을 읽어온 최초 시점을 스냅샷에 저장해둔 상태입니다.
3. Entity가 변경후 commit시 JPA가 1차캐시에 Entity - 스냅샷을 서로 비교합니다.
4. 변경됐을때는 SQL Update 쿼리가 진행됩니다.


플러시

영속성 컨텍스트의 변경 내용을 DB에 반영하는것입니다. 커밋이될때 또는 JPQL시 플러시가 발생됩니다.

플러시 발생

  1. 변경 감지
  2. 수정된 엔티티 쓰기지연 SQL 저장소에 등록
  3. 쓰기지연 SQL 저장소에 쿼리를 DB에 전송

단! JPQL 쿼리 실행시 플러시는 자동 실행

em.persist(memberA);
em.persist(memberB);
em.persist(memberC);

//중간에 JPQL 실행

query = em.createQuery("select m from Member m", Member.class);
// members에서는 memberA,memberB,memberC의 정보가 모두 조회 됨
List<Member> members= query.getResultList();

준영속 상태

영속 상태의 엔티티가 영속성 컨텍스트의 분리(detached)가 된 상태이며, 영속성 컨텍스트가 제공하는 기능을 사용하지 못합니다.

• em.detach(entity) : 특정 엔티티만 준영속 상태로 전환
• em.clear() : 영속성 컨텍스트를 완전히 초기화
• em.close() : 영속성 컨텍스트를 종료

profile
생각하는 개발자
post-custom-banner

0개의 댓글