

// 엔티티 매니저 팩토리 생성
// 비용이 아주 많이 든다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabook");
// 엔티티 매니저 생성, 비용이 거의 안든다.
EntityManager em = emf.createEntityManager();
여러 엔티티 매니저가 같은 영속성 컨텍스트에 접근할 수도 있다.


// 객체를 생성한 상태 (비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
em.find()나 JPQL을 사용해 조회된 데이터는 영속 상태이다.// 객체를 저장한 상태 (영속)
em.persist(member);
em.datach(), em.close(), em.clear() 호출 시 준영속 상태가 된다.// 객체를 삭제한 상태(삭제)
em.remove(member);
@Id로 테이블의 기본키와 매핑한 값)으로 구분한다.@Id로 매핑한 식별자고 값은 엔티티 인스턴스다.// 엔티티를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUsername("회원");
// 엔티티를 영속
em.persist(member);

EntityManager.persist()를 통한 영속객체 등록은 우선 해당 객체가 1차 캐시에 저장되고 일반적으로 트랜잭션이 커밋되는 시점에 Insert 쿼리가 데이터베이스에 반영된다.EntityManager.find()를 통한 데이터검색은 우선 1차 캐시를 통해 해당 객체를 검색하고 없을 경우 Select 쿼리를 통해 데이터베이스에석 검색을 수행한다.Member a = em.find(Member.class, "member1");
Member b = em.find(Member.class, "member1");
System.out.println(a == b); // 동일성 비교
JPA를 이용하면, member1이란 식별자(id)를 가진 객체를 반복해서 호출할 때 1차 캐시에 있는 같은 엔티티 인스턴스를 반환한다. 따라서 영속성 컨텍스트는 성능상의 이점과 엔티티의 동일성을 보장한다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
// 엔티티 매니저는 데이터 변경 시 트랜잭션을 시작해야 한다.
transaction.begin(); // [트랜잭션] 시작
em.persist(memberA);
em.persist(memberB);
// 여기까지 INSERT SQL을 데이터베이스에 보내지 않는다.
// 커밋하는 순간 데이터베이스에 INSERT SQL을 보낸다.
transaction.commit(); // [트랜잭션] 커밋
begin(); // 트랜잭션 시작
save(A);
save(B);
save(C);
commit(); // 트랜잭션 커밋
이 로직을 실행하는 2가지 방식이 있다.
save() 메서드를 호출할 때마다 즉시 DB에 등록 쿼리를 보내고 마지막에 트랜잭션을 커밋한다.트랜잭션 범위 안에서 실행되고, 커밋 시 함께 저장, 롤백 시 함께 취소 되므로 결과는 1번과 2번이 동일하다. 이 기능을 잘 활용하면 모아둔 등록 쿼리를 DB에 한 번에 전달해 기능을 최적화할 수 있다.
UPDATE MEMBER
SET
NAME=?,
AGE=?
WHERE
id=?
수정 쿼리는 수정 요소가 늘어날 때마다 SQL을 일일이 확인해야 하는 등, 비즈니스 로직을 분석하기 위해 SQL을 의존해야 하는 문제점이 있다. JPA는 이러한 수정 쿼리의 불편함을 변경 감지를 통해 해결한다.
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // [트랜잭션] 시작
// 영속 엔티티 조회
Member memberA = em.find(Member.class, "memberA");
// 영속 엔티티 데이터 수정
memberA.setUsername("hi");
memberA.setAge(10);
// em.update(member) 이런 코드가 있어야 하지 않을까?
trnasaction.commit(); // [트랜잭션] 커밋
JPA로 엔티티를 수정할 때는 단순히 엔티티를 조회해 데이터만 변경하면 된다. 이는 엔티티의 변경사항을 데이터베이스에 자동으로 반영하는 변경 감지(dirty checking) 덕분에 가능해진다.

flush())가 호출된다.UPDATE MEMBER
SET
NAME=?,
AGE=?,
GRADE=?,
...
WHERE
id=?
필드가 많거나 저장되는 내용이 너무 큰 경우, 수정된 데이터만 사용해 동적으로 UPDATE SQL을 생성하는 전략을 선택 가능하다. 이 경우 하이버네이트 확장 기능을 사용한다.
@Entity
@org.hibernate.annotations.DynamicUpdate
@Table(name="Member")
public class Member {...}
Member memberA = em.find(Member.class, "memberA") // 삭제 대상 엔티티 조회
em.remove(memberA); // 엔티티 삭제
remove()를 이용한다.em.remove(memberA) 호출 시점에 memberA는 영속성 컨텍스트에서 제거된다.flush())em.persist(memberA);
em.persist(memberB);
em.persist(memberC);
// 중간에 JPQL 실행
query = em.createQuery("select m from Member m", Member.class);
List<Member> members = query.getResultList();
em.persist()를 호출해 3개의 멤버를 영속성 컨텍스트에 올렸으나 DB에는 반영되지 않았다. 이 상황에서 JPQL이 실행된다면 어떻게 될까?참고) 식별자를 기준으로 조회하는 find() 메서드 호출 시 플러시를 실행하지 않는다.
em.setFlushMode(FlushModeType.COMMIT)
public void testDetached() {
...
// 회원 엔티티 생성, 비영속 상태
Member member = new Member();
member.setId("memberA");
member.setUsername("회원A");
// 회원 엔티티 영속 상태
em.persist(member);
// 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
em.detach(member);
transaction.commit();
// 엔티티 조회, 영속 상태
Member member = em.find(Member.class, "memberA");
em.clear(); // 영속성 컨텍스트 초기화
// 준영속 상태
member.setUsername("changeName");
public void closeEntityManager() {
EntityMangerFactory emf = Persistence.creatEntityManagerFactory("jpabook");
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin() // [트랜잭션] - 시작
Member memberA = em.fiind(Member.class, "memberA");
Member memberB = em.fiind(Member.class, "memberB");
transaction.commit(); //[트랜잭션] - 커밋
em.close(); // 영속성 컨텍스트 닫기(종료)
준영속 상태인 회원 엔티티는 어떻게 되는걸까?
merge()을 사용하면 된다.merge(): 준영속 상태의 엔티티를 받아 그 정보로 새로운 영속 상태의 엔티티를 반환한다.