엔티티 매니저//엔티티 매니저 공장 만들기, 비용이 아주 많이 든다!
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 프로그래밍(김영한)