본문 바로가기

JPA 프로그래밍

[자바 ORM 표준 JPA 프로그래밍] 영속성 관리

- JPA에서 가장 중요한 2가지

  • 객체와 관계형 데이터베이스 매핑하기
    • Object Relational Mapping
  • 영속성 컨텍스트(실제로 내부에서 어떻게 작동하는지?)

 

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

 

- 영속성 컨텍스트

  • 엔티티를 영구 저장하는 환경
  • EntityManager.persist(entity);
    • '엔티티 객체를 DB에 저장하는 구나'라고 생각하고 있습니다.
    • 하지만 실제로는 영속성 컨텍스트에 저장을 합니다.
  • 논리적인 개념
  • 엔티티 매니저를 통해서 영속성 컨텍스트에 접근

 

- 엔티티의 생명주기

  • 비영속 ( new / transient)
    • 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
    •  
    • // 객체를 생성한 상태 ( 비영속 )
      Member member = new Member();
      member.setID('member1');
  • 영속 ( managed )
    • 영속성 컨텍스트에 관리되는 상태 ( insert Query 실행 전)
      • persist로 저장
      • em.finf()로 조회
    • EntityManager em = entityManagerFactory.createEntityManager();
      // 영속
      em.persist(member);
  • 준영속( detached )
    • 영속성 컨텍스트에 저장되었다가 분리된 상태
    • // 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
      em.detach(member);
  • 삭제 ( removed )
    • 삭제된 상태
    • // 객체를 삭제한 상태 ( 삭제 )
      em.remove(member);

 

- 영속성 컨텍스트의 이점

  • (1) 1차 캐시
    • Member member = new Member();
      member.setId("member1");
      member.setUsername("회원1");
      
      // 1차 캐시에 저장됨
      em.persist(member);
      
      // 1차 캐시에서 조회
      Member findMember = em.find(Member.class, "member1");
    • 트랜잭션 별로 공유하는 캐시(1차 캐시)라서 시스템에 크게 영향을 주지 않음. 그러나 비즈니스 로직이 큰 경우에는 도움을 줌
      • 다른 트랜잭션에 1차 캐시는 공유 안됨( 2차 캐시 가능)
      • 조회 쿼리가 실행되지 않고 1차 캐시에서 조회
  • (2) 동일성( identity ) 보장
    • Member a = em.find(Member.class, "member1");
      Member b = em.find(Member.class, "member1");
      
      //동일성 비교 true
      System.out.println( a == b ); 
      
      /*
      == : 주소 값 비교
      equals : 객체 값 비교
      */
  • (3) 트랜잭션을 지원하는 쓰기 지연( transactional write-behind )
    • ...
      EntityTransaction transaction = entityManager.getTransaction();
      ...
      
      
      em.persist(memberA);
      em.persist(memberB);
      // 여기까지 INSERT SQL을 데이터베이스에 보내지 않느다.
      
      // 커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
      transaction.commit(); // [트랜잭션] 커밋
    • 실행할 쿼리들을 모았다가 한번에 쿼리 실행
  • (3) 변경 감지( Dirty Checking )
    • EntityManager em = entityManagerFactory.createEntityManager();
      EntityTransaction tx = em.getTransaction();
      tx.begin();	// [트랜잭션] 시작
      
      // 영속 엔티티 조회
      Member memberA = em.find(Member.class, "memberA");
      
      // 영속 엔티티 데이터 수정
      memberA.setUsername("oss0202");
      memberA.setAge(29);
      
      //em.update(member) 이런 코드가 있어야 할꺼 같지만, 필요 없음
      
      tx.commit();// [트랙잭션] 커밋
      • 플러시( flush )
        • 영속성 컨텍스트의 변경내용을 데이터베이스에 반영
        • 플러시 발생
          • 변경감지
          • 영속성 컨텍스트를 비우지 않음
          • 영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
          • 트랜잭션이라는 작업 단위가 중요 
            • 커밋 직전에만 동기화하면 됨
          • 수정된 엔티티 쓰기 지연 SQL 저장소에 등록
          • 영속성 컨텍스트를 플러시 하는 방법
            • em.flush() - 직접 호출
            • 트랜잭션 커밋 - 플러시 자동 호출
            • JPQL 쿼리 실행 - 플러시 자동 호출
              • em.persist(memberA);
                em.persist(memberB);
                em.persist(memberC);
                // 플러시가 호출이 되지 않으면 아래 JPQL 결과가 아무것도 안나오게 된다.
                
                // 중간에 JPQL 실행
                query = em.createQuery("selec m from Member m", Member.class);
                List<Member> members = query.getResultList();
      • 준영속 상태
        • 영속 상태
          • 영속성 컨텍스트의 1차 캐시에 올라간 상태. 엔티티 매니저가 관리하는 상태
          • em.persist()로 영속성 컨텍스트에 저장한 상태도 영속 상태
          • em.find()로 조회를 할 때, 영속성 컨텍스트 1차 캐시에 없어서 DB에서 조회한 후에, 1차 캐시에 저장한 상태도 영속상태
          • // 1차 캐시에 없으므로, DB에서 조회한 엔티티를 영속선 컨텍스트에 올림(1차 캐시에 넣음) -> 영속 상태
            Member.em.find(Member.class, 10L);
            
            // Dirty Checking이 발생하여 1차 캐시의 엔티티와 스냅샷이 다른 것을 감지하고 Update 쿼리 실행
            member.setName("oss0202");
            transaction.commit();
        • 준영속 상태
          • 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 상태( detached )
            • // 1차 캐시에 없으므로, DB에서 조회한 엔티티를 영속선 컨텍스트에 올림(1차 캐시에 넣음) -> 영속 상태
              Member.em.find(Member.class, 10L);
              
              // Dirty Checking이 발생하여 1차 캐시의 엔티티와 스냅샷이 다른 것을 감지하고 Update 쿼리 실행
              member.setName("oss0202");
              
              // 영속 컨텍스트에서 분리하기
              em.detach(member); // update 쿼리가 실행 안됨
              
              // 영속성 컨텍스트를 통으로 분리하기( 완전 clear )
              em.clear();
              
              // 영속성 컨텍스트 종료(닫기)
              em.close();
              
              transaction.commit();
              
            • 000
    • JPA는 엔티티를 변경하면 자동으로 Update가 된다고 생각하고 코드를 작성
  • (4) 지연 로딩( Lazy Loading )
    • ex. member.getTeam()을 했을 때 나중에 쿼리를 실행
    • 실무에서 아주 중요한 기능
    • 뒤에 강의에서 자세하게 설명

 

 

 

출처

https://www.inflearn.com/course/ORM-JPA-Basic/dashboard

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 본 강의는 자바 백엔

www.inflearn.com