- 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);
- 영속성 컨텍스트에 관리되는 상태 ( insert Query 실행 전)
- 준영속( 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
-
- 영속 상태의 엔티티가 영속성 컨텍스트에서 분리된 상태( detached )
- 영속 상태
- 플러시( flush )
- JPA는 엔티티를 변경하면 자동으로 Update가 된다고 생각하고 코드를 작성
-
- (4) 지연 로딩( Lazy Loading )
- ex. member.getTeam()을 했을 때 나중에 쿼리를 실행
- 실무에서 아주 중요한 기능
- 뒤에 강의에서 자세하게 설명
출처
https://www.inflearn.com/course/ORM-JPA-Basic/dashboard
'JPA 프로그래밍' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 엔티티 매핑 - 필드와 컬럼 매핑, 기본키 매핑 ( 2/3 ) (0) | 2021.06.29 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] 엔티티 매핑 - 객체와 테이블 매핑, DB 스키마 자동 생성( 1/3 ) (0) | 2021.06.29 |
[자바 ORM 표준 JPA 프로그래밍] Hello World 프로젝트 ( 2/2 ) (0) | 2021.06.13 |
[자바 ORM 표준 JPA 프로그래밍] Hello World 프로젝트 ( 1/2 ) (0) | 2021.06.13 |
[자바 ORM 표준 JPA 프로그래밍] 들어가며 (0) | 2021.06.10 |