JPA의 핵심은 다음 두가지다.
- 객체와 관계형 데이터베이스 매핑(object relational mapping) - ORM
- 영속성 컨텍스트
영속성 컨텍스트란?
- 엔티티를 영구 저장하는 환경이라고 이해할 수 있다.
- 엔티티 매니저를 통해 영속성 컨텍스트에 접근할 수 있다.
엔티티 생명주기
- 비영속(new) : 영속성 컨텍스트와 전혀 관계없는 상태
Member member = new Member();
member.setId("member1");
member.setUserName("회원1");
- 영속(managed): 영속성 컨텍스트에 관리되는 상태
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
//객체를 저장한 상태(영속)
em.persist(member);
- 준영속(detached): 영속성 컨텍스트에 저장되었다가 분리된 상태
em.detach(member); // 특정 엔티티만 준영속 상태로 전환
em.clear(); // 영속성 컨텍스트를 초기화
em.close(); // 영속성 컨텍스트를 종료
- 삭제(removed): 삭제된 상태
em.remove(member);
영속성 컨텍스트의 장점은?
- 1차 캐시
//1차 캐시에 저장됨
em.persist(member);
//1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");
find 시 영속 컨텍스트 내의 1차 캐시를 먼저 확인하여 1차 캐시에 데이터가 있는 경우 데이터베이스에서 값을 가져오는 게 아니라 캐시에서 값을 가져옴.
1차 캐시의 구조는 @id, entity로 이루어지기 때문에 PK값으로 불러온다고 생각할 수 있다.
1차캐시에 값이 없어 DB에서 값을 가져오는 경우에도 이를 1차 캐시에 저장하여 후에 재활용할 수 있도록 한다.
- 동일성 보장
Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); //동일성 비교 true
- 트랜잭션을 지원하는 쓰기 지연
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
- 변경 감지(Dirty checking)
// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
//em.update(member) 이런 코드가 있어야 하지 않을까? -> 없어도 됨
transaction.commit(); // [트랜잭션] 커밋
원리: 영속 컨텍스트 내부에서 엔티티와 스냅샷을 비교하여 변경이 있을 경우 자동으로 update 쿼리를 날려준다.
+) em.remove(member);를 통해 삭제 시에도 자동으로 업데이트가 이루어짐
- 지연 로딩(Lazy loading)
나중에 배움!
플러시란?
영속성 컨텍스트의 변경 내용을 DB에 반영하는 것.
em.flush()를 통해 직접 호출할 수도 있고 트랜잭션 커밋 시에 플러시가 자동 호출되기도 한다.
+) JPQL 쿼리 실행 시에도 플러시가 자동 호출됨.
------------------------------------------------------------------------------
*레퍼런스 : 인프런 김영한님 강의(자바 ORM 표준 JPA 프로그래밍)
댓글