영속성 컨텍스트는 JPA에서 나오는 개념이다
JPA를 이해하기 위해서는 가장 중요한 2가지 개념이 있는데
하나는 객체와 관계형 데이터베이스 매핑하기(Object Relational Mapping)
두 번째는 바로 영속성 컨텍스트가 있다.
영속성 컨텍스트를 이해하는 것이 실제로
JPA가 내부에서 실제로 어떻게 동작하는지 이해하는데 가장 큰 중요한 대목이 될 것이다.
영속성 컨텍스트를 이해하기 위해서는
엔티티의 영속을 관리하는 엔티티 매니저와
엔티티 매니저를 관리하는 엔티티 매니저 팩토리를 이해할 필요가 있다.
엔티티 매니저 팩토리는
들어오는 요청에 따라 엔티티 매니저를 생성한다.
그리고 엔티티 매니저는 영속을 위해 데이터베이스와 연결하기 전,
커넥션 풀을 사용하여 영속을 준비한다 (persist)
영속성 컨텍스트란, 엔티티를 영구적으로 저장하는 환경이라는 걸 말한다.
EntityManager.persist(entity) >> 엔티티 매니저를 통해서 엔티티를 영속성 컨텍스트에 저장하는 것 DB에 저장하는 것이 아니다.
영속성 컨텍스트는 논리적인 개념이다. 눈에 보이지 않는다.
엔티티는 엔티티 매니저를 통해 영속성 컨텍스트에 접근한다.
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.List;
public class JpaMain {
public static void main(String[] args) {
// src/main/resources/META-INF/persistence.xml
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
// 위의 엔티티 매니저는 최초에만 만들어주면 된다.
Member findMember = em.find(Member.class, 1L);
findMember.setName("Hello JPA");
// DB에서 트랜잭션이란 단위는 중요하다
em.persist(findMember);
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
em.close();
}
// code
emf.close();
// close를 해줘야 리소스들이 반환된다.
}
}
엔티티의 생명주기는 총 4가지가 있다.
(1) 비영속 (new/transient)
: 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태이다.
(2) 영속 (managed)
: 영속성 컨텍스트에 관리되는 상태이다
(3) 준영속 (detached)
: 영속성 컨텍스트에 저장되었다가 분리된 상태이다
(4) 삭제 (removed)
: 삭제된 상태이다.
비영속
객체를 생성하고, 엔티티 매니저와 아무 상관이 없는 상태이다.
Member member = new Member();
member.setId("member1");
member.setName("회원1");
영속
객체를 저장한 상태(영속)
// 객체를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setName("회원1");
EntityManager em = emf.createEntityManager();
em.getTransaction.begin();
// 객체를 저장한 상태(영속)
em.persist(member);
준영속 ==> em.detach(member);
// 회원 엔티티를 영속성 컨텍스트에서 분리, 준영속 상태
삭제 ==> em.remove(member);
// 객체를 삭제한 상태(삭제)
영속성 컨텍스트의 이점은 5가지가 있다.
(1) 1차 캐시
(2) 동일성(identity) 보장
(3) 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)
(4) 변경 감지(Dirty Checking)
(5) 지연 로딩(Lazy Loading)
엔티티 조회, 1차 캐시
// 엔티티를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUserName("회원1");
// 엔티티를 영속
em.persist(member);
persist 한다고 해서, 데이터베이스에 저장되는 것이 아니다.
commit을 해야 데이터베이스에 저장된다.
persist를 함으로써 "member1"을 1차 캐시에 저장한 것으로 보면 된다.
1차 캐시에서 조회
// 엔티티를 생성한 상태(비영속)
Member member = new Member();
member.setId("member1");
member.setUserName("회원1");
// 1차 캐시에 저장됨
em.persist(member);
// 1차 캐시에서 조회
Member findMember = em.find(Member.class, "member1");
만약에 "member2"를 find 했을 때 1차 캐시에 없으면 DB에서 조회해온다.
Member findMember2 = em.find(Member.class, "member2");
데이터 트랜잭션이 끝나면 영속성 컨텍스트를 지운다.
1차 캐시는 데이터 트랜잭션 한 번에 끝나기 때문에 여러 사람이 사용해도 다 제각각으로 작동한다.
1차 캐시는 공유자원이 아니다.
fnd를 두번 이상 연속 사용해도 같은 엔티티를 찾는거면 한번만 쿼리를 날리고 1차 캐시에 데이터를 저장했기 때문에
두 번 이상 쿼리를 날리지 않는다
영속 엔티티의 동일성 보장
Member a = em.find(entity);
Member b = em.find(entity);
System.out.println(a == b);
a == b 가 true 이다.
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(); // [트랜잭션] 커밋
결론적으로 commit을 해야 데이터가 DB에 등록된다.
엔티티 수정 - 변경 감지(dirty chekcing)
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) 이런 코드가 있어야 하지 않을까?
transaction.commit(); // [트랜잭션] 커밋
별도의 update 문을 실행하지 않아도 된다.
데이터를 find로 찾아온 후 데이터가 변경되면 알아서 update 문을 실행한다.
엔티티 삭제
//삭제 대상 엔티티 조회
Member memberA = em.find(Member.class, “memberA");
em.remove(memberA); //엔티티 삭제
'자바 > JPA' 카테고리의 다른 글
[JPA/JAVA] 다양한 연관관계 매핑 (N:1, 1:N, 1:1, N:M) (0) | 2023.02.20 |
---|---|
[JPA/java] 연관관계 매핑 (단방향, 양방향, 객체, 테이블, 기본키, 외래키 등) (3) | 2023.01.25 |
[JPA/Java] 엔티티 매핑 (객체, 테이블, 필드, 컬럼, 기본 키 등) (0) | 2023.01.22 |
[JPA/JAVA] 플러시 & 준영속 상태 (2) | 2023.01.12 |
[Java/JPA] JPA 개념 (0) | 2021.10.15 |
댓글