2023. 1. 8. 19:14ㆍjpa
영속성 컨테스트란?
엔티티를 영구 저장하라는 뜻이다.

jpa는 웹 어플리케이션에 요청이 오면 EntityManagerFactory에서 EntityManager를 생성을 한 후 커넥션풀을 활용해 db에 접근하여 데이터를 저장하게 되는 과정이 일어난다.
엔티티의 생명주기
1. 비영속
Member member = new Member();
member.setId(100L);
member.setName("Hello");

객체를 생성만 했을 경우에는 영속 컨텍스트 밖에 위치한다. 이러한 경우를 비영속 상태라고 한다.
2. 영속
Member member = new Member();
member.setId(100L);
member.setName("Hello");
em.persist(member);

em.persist를 하면 객체가 영속 컨테스트 안에 들어가게 되면서 영속 상태가 된다.
그렇다면 언제 쿼리문 생성되는지 알아보자
Member member = new Member();
member.setId(100L);
member.setName("Hello");
System.out.println("Before");
em.persist(member);
System.out.println("After");
tx.commit();
Before
After
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(name, id)
values
(?, ?)
밑에 결과 확인해보면 em.persist를 하는 부분에서 생성되는게 아니라 커밋을 할 때 생성되는 것을 알 수 있다.
그렇다면 em.persist를 하면 영속 컨테스트 안에서는 무슨 일이 발생할까?
영속성의 이점으로 1차 캐시가 있다.

영속 컨테스트 안에는 1차 캐시라는 것이 있는데 Map의 형태로 @ID는 pk값, Entity는 객체가 들어가게 된다.
Member member = new Member();
member.setId(2L);
member.setName("회원1");
em.persist(member);
Member findMember = em.find(Member.class, 2L);
1차 캐시는 트랜잭션 시작되면 생성되었다가 트랜잭션이 종료되면 없어지게 되는데 위의 코드는 같은 트랜잭션 안에 있는 상태이다. 이러한 경우에는 영속 상태의 객체를 찾을 경우 db에서 조회하는 것이 아니라 1차 캐시에서 조회하게 된다.
Member member = new Member();
member.setId(3L);
member.setName("회원3");
em.persist(member);
Member findMember = em.find(Member.class, 3L);
tx.commit();
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(name, id)
values
(?, ?)
영속 상태인 객체를 commit을 하면 insert 쿼리문이 생성되면서 db에 저장이 된다. 여기서 select쿼리문이 생기지 않는 이유는 1차 캐시에서 확인이 가능하기 때문이다.
Member findMember = em.find(Member.class, 3L);
다시 시작하면 같은 트랙잭션이 아니기 때문에 1차 캐시에 있던 내용은 초기화가 된다. db에 있는 정보를 1차 캐시로 가져오기 위해 select문이 실행되게 된다.
Hibernate:
select
member0_.id as id1_0_0_,
member0_.name as name2_0_0_
from
Member member0_
where
member0_.id=?
영속성의 이점으로 같은 트랜잭션 내에서 동일성을 보장해준다는 것이다.
Member a = em.find(Member.class, 3L);
Member b = em.find(Member.class, 3L);
System.out.println(a == b);
마치 자바의 컬렉션처럼 동작하는 것을 확인할 수 있다.
영속성의 이점으로 트랜잭션을 지원하는 쓰기 지연이 있다.
Member member1 = new Member();
member1.setId(200L);
member1.setName("회원200");
Member member2 = new Member();
member2.setId(201L);
member2.setName("회원201");
em.persist(member1);
em.persist(member2);
System.out.println("---------------------");
tx.commit();
---------------------
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(name, id)
values
(?, ?)
Hibernate:
/* insert hellojpa.Member
*/ insert
into
Member
(name, id)
values
(?, ?)
persist를 하게 되면 1차 캐시에 저장되고 쓰기 지연 저장소에 쿼리문이 저장되게 된다. commit을 하기 전까지 가지고 있다가 commit을 하면 한번에 쿼리문을 날려준다. 이를 통해 얻을 수 있는 점은 최적화를 할 수 있다는 점이다. 배치를 예로 들 수 있을 거 같다.
영속성의 이점으로 변경 감지(dirty check)가 있다.

Member member = em.find(Member.class, 200L);
member.setName("HelloJpa");
System.out.println("---------------------");
tx.commit();
/* update
hellojpa.Member */ update
Member
set
name=?
where
id=?
변경 감지는 기존에 저장 되어 있던 스냅샷과 entity에 저장되어 있는 객체를 비교하는 방식으로 진행된다. 비교해서 다른 경우에는 자바의 컬렉션처럼 값을 변경만 해주면 update 쿼리가 실행되게 된다.
3. 준영속
준영속 상태는 영속 상태의 엔티티를 영속성 컨테스트에서 분리하는 것을 의미한다.
em.detach(entity)
em.clear()
em.close()
4. 삭제
Member member = em.find(Member.class, 200L);
em.remove(member);
System.out.println("---------------------");
tx.commit();
Hibernate:
select
member0_.id as id1_0_0_,
member0_.name as name2_0_0_
from
Member member0_
where
member0_.id=?
---------------------
Hibernate:
/* delete hellojpa.Member */ delete
from
Member
where
id=?
플러시
영속성 컨텍스트의 변경내용을 데이터베이스에 반영하는 것을 말한다.
오개념이 있거나 보충해주실 내용있으면 댓글에 적어주면 감사하겠습니다.
'jpa' 카테고리의 다른 글
| jpa - 다양한 연관관계 매핑 (0) | 2023.06.24 |
|---|---|
| jpa 연관매핑 기초 - 단방향, 양방향 (0) | 2023.06.22 |
| java: Compilation failed: internal java compiler error (0) | 2023.06.20 |
| jpa 엔티티 매핑 정리 (0) | 2023.06.20 |
| jpa 영속성 정리 (0) | 2023.06.17 |