엔티티 매니저
//엔티티 매니저 공장 만들기, 비용이 아주 많이 든다!
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("jpabook");
//공장에서 엔티티 매니저 생성, 비용이 거의 안 든다!
EntityManager em = emf.createEntityManager();
EntityManager
: 엔티티
의 CRUD
일 처리
엔티티
를 영구 저장하는 환경엔티티 매니저
를 통해 영속성 컨텍스트
에 엔티티를 보관/관리EntityManager.persist(entity);
사용Entity
: DB
와 연결되는 객체
엔티티
의 생명주기new
/transient
)JPA
와 전혀 관계 없는 새로운
상태Member member=new Member();
member.setId("member1");
member.setUsername("회원1");
managed
)영속성 컨텍스트
가 관리하는 상태em.find()
나 JPQL
로 조회된 엔티티
도 영속 상태!!!EntityManager em=emf.createEntityManager();
em.getTransaction().begin();
em.persist(member); //객체를 저장
detached
)영속성 컨텍스트
에서 저장 되었다가 분리
된 상태엔티티
는 DB
에도 저장되어 있지만, 연결되지 않음em.detach(member);
removed
)em.remove(member);
영속성 컨텍스트
는 엔티티
를 식별자 값
으로 구분영속 상태
는 식별자 값
이 반드시 필요
!!!Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
//1차 캐시에 저장됨
em.persist(member);
//1차 캐시에서 조회 : find(클래스, 아이디) 형태
Member findMember = em.find(Member.class, "member1");
//------
// EntityManger.find() 메소드 정의
public <T> T find(Class<T> entityClass, Object primaryKey)
1차 캐시
: 영속성 컨텍스트
내부의 캐시컨텍스트
내부 Map
형태로 존재@Id
(식별자)엔티티
1차 캐시
에서 조회1차 캐시
에 없으면 DB
에서 조회1차 캐시
에 저장영속 상태
의 엔티티
반환em.find
로 가져온 두 값의 동일성을
보장!참조값
이 동일1차 캐시
에서 같은 엔티티
를 가져옴1차 캐시
로REPEATABLE READ
) 등급의 트랜잭션 격리 수준을애플리케이션 차원
에서 제공!EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
//엔티티 매니저는 데이터 변경 시 트랜잭션을 시작해야 한다.
transaction.begin(); //[트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
//여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
//커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); //[트랜잭션] 커밋
transaction.begin();
: 트랜잭션 시작em.persist(memberA);
: 내부 쓰기 지연 SQL 저장소
에 데이터들을 저장transaction.commit();
: 커밋
시 데이터(쓰기 지연 SQL 저장소
에 모인 쿼리
)를 한번에 DB
에 전송// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
//-> 커밋 시 자동으로 데이터 업데이트
null
값 들어감ㅠ비즈니스 로직
이 SQL
에 의존ㅠ엔티티
의 변경사항을 DB
에 자동 반영엔티티
와 스냅샷
비교영속성 컨텍스트
의 변경 내용을 데이터베이스에 동기화
영속성 컨텍스트
를 비우지는 않음!!!트랜잭션
단위로, 커밋 직전
에만 동기화하면 됨!엔티티
영속 상태
엔티티
가 수정된 후, 쓰기지연 SQL 저장소
로 보내진 수정 쿼리
DB
에 저장DB
트랜잭션 커밋업데이트 SQL 문은 실제로,
엔티티
의모든 필드
를 수정에 반영한다!
수정 쿼리
가 항상 같아재사용
용이!
- 어플리케이션 로딩 시점에
수정 쿼리
를 미리 생성 후 재사용!DB
에 동일 쿼리 전달 →DB
는 이전에 파싱된 쿼리를 재사용!- 만일 수정 데이터만 사용한
동적 UPDATE SQL
원할 시(칼럼 30개 이상)
하이버네이트
확장 기능 사용@org.hibernate.annotations.DynamicUpdate
em.flush()
: 직접 호출(자주 안씀)트랜잭션 커밋
시 자동 호출JPQL 쿼리 실행
시 자동 호출find()
메소드 호출 시엔 플러시 실행 안됨!FlushModeType.AUTO
: 커밋이나 쿼리 실행 시 플러시(기본 값)FlushModeType.COMMIT
: 커밋 시 플러시영속성 컨텍스트
기능 사용 X!엔티티
관련된 모든 SQL 저장소 쿼리들
도 제거됨!em.detach(entity)
: 특정 엔티티
만 준영속
상태로 전환em.clear()
: 영속성 컨텍스트
를 완전히 초기화
컨텍스트
속 모든 엔티티
를 준영속
상태로 전환em.close()
: 영속성 컨텍스트
를 종료
준영속
전환됨비영속
상태식별자 값
이 들어가 있다newEntity=em.merge(entity)
entity=em.merge(entity)
entity = new Entity("헌치")
em.persist(entity)
두 방식의 차이점은??
Spring Data JPA
에서는 두 기능이 통합된 save(entity)
메소드 사용save
메서드는 merge
인지, persist
인지 관계없이 return
값으로 반드시 영속성이 보장되는 인스턴스를 반환하도록 구현준영속
엔티티
에 대한 영속 상태 엔티티
를 반환파라미터
로 넘어온 엔티티
의 식별자 값
으로 영속성 컨텍스트
를 조회엔티티
가 없으면 DB
에서 조회엔티티
를 저장
하거나, 업데이트
하거나!준영속
엔티티
는 여전히 준영속
상태로 남아있다엔티티
는 서로 다른 인스턴스
!em.remove(entity)
: 해당 엔티티
를 삭제호출 직후
: 엔티티
를 영속성 컨텍스트
에서 제거플러시
: SQL 저장소
속 삭제 쿼리
호출![책, 강의]
자바 ORM 표준 JPA 프로그래밍
(김영한
)