엔티티를 영구 저장하는 환경이다.
전에는 .persist()
메소드가 단순히 데이터를 저장한다고만 했었지만
사실은 엔티티를 영속성 컨텍스트 안에 저장한다.
이 영속성 컨텍스트는 엔티티 매니저를 생성할 때 만들어지며 엔티티 매니저를 통해서 접근, 관리 할 수 있다.
위 처럼 엔티티가 생성되며 사용되는데, 엔티티의 생명주기는 다음과 같다.
.detach()
메서드가 호출되어 영속성 컨텍스트가 초기화되거나
.close()
를 통해 영속성 컨텍스트가 닫히게 되면 준영속 상태가 된다..remove()
를 통해서 삭제를 하게된다.1차 캐시
Member member = new Member();
member.setId("member1");
member.setUsername("회원1");
em.persist("회원1"); // 엔티티 저장 = 1차 캐시에 저장
// 영속성 컨텍스트 안에 들어가게 되며 영속 상태가 되는 것
Member findMemeber = em.find(Member.class, "member1");
// 1차 캐시에서 조회하게 됨
Member findMemeber2 = em.find(Member.class, "member2");
// DB에서 조회하고, 1차 캐시에 저장하게 됨
em.find()
를 호출 하면 먼저 메모리에 있는 1차 캐시에서 엔티티를 찾는다.
동일성 보장
Member member1 = em.find(Member.class, "member1");
Member member2 = em.find(Member.class, "member1");
Sytem.out.println(member1 == member2); // 같은 주소 값 보장
트랜잭션을 지원하는 쓰기 지연
Entity Manager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // 트랜잭션 시작
em.persist(memeber1);
em.persist(member2);
//얼핏 보기에는 DB에 바로 저장할 거 같지만 쿼리 저장소에 보관해두게된다.
transaction.commit(); // 트랜잭션 저장 (커밋)
em.persist();
를 통해서 쿼리 저장소에 쿼리문들을 저장하게되고,
transaction.commit();
을 통해서 모아둔 쿼리를 DB에 보내게된다.flush()
하여 영속성 컨텍스트의 변경내용을 동기화한다.변경 감지
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
transaction.begin(); // 트랜잭션 시작
Member member1 = em.find(Meber.class, "member1"); // 영속상태의 엔티티 조회
member1.setUsername("hi");
member.setAge(10); // 영속상태의 데이터 수정
// em.update()?
transaction.commit(); // 트랜잭션 커밋
JPA는 영속 상태의 엔티티를 변경하면 em.update();
와 같은 코드가 없어도
변경사항을 감지하여 데이터베이스에 자동으로 반영하는 기능을 가지고 있다.
이를 바로 변경감지라고 한다.
commit()
을 사용하면 flush()
를 통해서 스냅샷과 엔티티를 비교하게 되고,
변경된 엔티티를 찾아 업데이트를 진행하게 된다.여기서 중요한점은 영속 상태의 엔티티여야만 한다는 점이다.
만약 준영속이거나 삭제된 엔티티의 값을 변경하면 반영되지 않는 것을 볼 수 있다.
이렇게 업데이트를 진행하게 되면 수정된 데이터에 대한 쿼리문이 작성될 것 같지만 예상 외로 그렇지않다.
UPDATE MEMBER
SET
NAME = ?,
AGE = ?,
GRADE = ?,
...
WHERE
ID = ?;
위와 같이 모든 필드를 사용해서 업데이트 문을 작성하게된다.
물론 필드가 많아지거나 저장되는 내용이 너무 커지게 되면 UPDATE 문을 동적으로 생성하는 것이 효율이 좋기에 그 때는 Hibernate의 동적 update를 사용하면 된다.
@org.hibernate.annotations.DynamicUpdate
참고로 INSERT 문도 존재하는 데이터 값만 골라서 동적으로 생성해주는
@DynamicInsert
가 있다.
지연 로딩
em.detach()
em.clear()