728x90
반응형
- 영속성이란?
- 데이터를 생성한 프로그램이 종료되어도 사라지지 않는 데이터의 특성을 말한다.
- 영속성을 갖지 않으면 데이터는 메모리에서만 존재하게 되고 프로그램이 종료되면 해당 데이터는 모두 사라지게 된다.
- 그래서 데이터를 파일이나 DB에 영구 저장함으로써 데이터에 영속성을 부여한다.
- 영속성 컨텍스트란?
- 엔티티(Entity)를 영구 저장하는 환경
- Application과 데이터베이스 사이에서 객체를 보관하는 가상의 저장소 같은 역할
- 엔티티 매니저(Entity Manager)를 통해 영속성 컨텍스트에 접근
- EntityManager를 통해 Entity를 저장, 조회하면 EntityManager는 영속성 컨텍스트에 해당 Entity를 보관하고 관리
- 영속성 컨텍스트 생명주기
- 비영속(new): 영속성 컨텍스트와는 무관한 상태
- 영속(managed): 영속성 컨텍스트에 저장된 상태
- 준영속(detached): 영속성 컨텍스트에 저장되었다가 분리된 상태
- 삭제(removed): 영속성 컨텍스트에서 삭제된 상태
3-1. 비영속(new)
- Entity 객체를 생성했지만, 아직 영속성 컨텍스트에는 저장되지 않은 상태(순수 객체)
// 순수 객체
Member member = new Member();
3-2 영속(Managed)
- Entity Manager를 통해서 Entity를 영속성 컨텍스트에 저장한 상태
- 해당 객체는 영속성 컨텍스트에 의해 관리된다는 의미
// 순수 객체
Member member = new Member();
// 영속성 컨텍스트에 저장 -> 영속성 컨텍스트가 관리
EntityManager em;
em.persist(member);
3-3 준영속(Detached)
- 영속성 컨텍스트가 관리하던 상태에서 엔티티를 더이상 관리하지 않는 상태
- 준영속 상태의 특징
- 1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩을 포함한 영속성 컨텍스트가 제공하는 어떠한 기능도 동작하지 않는다.
- 식별자 값을 가지고 있다.
// 엔티티를 영속성 컨텍스트에서 분리
em.detach(member);
// 영속성 컨텍스트를 비움(초기화)
em.clear();
// 영속성 컨텍스트 종료
em.close();
- 엔티티를 준영속 상태로 전환하는 방법
- detach(entity)
- 특정 엔티티만 준영속 상태로 전환(영속성 컨텍스트로부터 분리)
- 1차 캐시, 쓰기 지연, SQL 저장소 정보 제거
- 영속성 컨텍스트 안에서의 Insert, Update 쿼리도 제거되어 DB에 저장되지 않는다.
- clear()
- 영속성 컨텍스트를 완전히 초기화
- 영속성 컨텍스트의 모든 엔티티를 준영속 상태로 만든다
- 영속성 컨텍스트 틀은 유지하지만 내용은 비워 새로 만든 것과 같은 상태
- close()
- 영속성 컨텍스트를 종료
- 해당 영속성 컨텍스트가 관리하던 영속성 상태의 엔티티들은 모두 준영속 상태로 변경
엔티티를 영속 상태로 전환하는 방법
- merge(entity)
- 준영속 상태의 엔티티를 다시 영속 상태로 변경(병합)
- 파라미터로 전달된 엔티티의 식별자 값으로 영속성 컨텍스트를 조회하고 엔티티가 없다면 DB에서 조회
- 만약 DB에도 없다면 새로운 엔티티를 생성하여 병합
- 병합은 save(저장) 또는 update(수정) 기능 수행
3-4 삭제(Remove)
- 엔티티를 영속성 컨텍스트와 DB에서 삭제
em.remove(member);
4. 특징
- 엔티티 매니저(Entity Manager)를 생성할 때 영속성 컨텍스트(Persistence Context)도 생성 (1:1)
- 엔티티 매니저를 통해 해당 영속성 컨텍스트에 접근, 관리 할 수 있음
- 엔티티를 식별자 값(@id로 매핑한 값)으로 구분
- 영속성 상태에는 식별자 값이 반드시 있어야 한다.(없으면 예외 발생)
트랜잭션을 Commit 하는 순간 영속성 컨텍스트에 새로 저장된 엔티티(Entity)를 DB에 반영
- 영속성 상태에서 값을 여러 번 바꾸어도 마지막 트랜잭션을 커밋하는 순간 값으로 반영(flush)
영속성 상태의 엔티티는 모두 영속성 컨텍스트에서 관리
- 내부 캐시(1차 캐시)에 저장
- 동일성 보장
- 트랜잭션을 지원하는 쓰기 지연
- 변경 감지
- 지연 로딩
- 예시
- Member Entity
@Entity
@Getter
@Setter
public class Member{
@Id
private String id;
private String name;
}
// 엔티티 생성(비영속 = 순수객체)
Member member = new Member();
member.setId("member1");
member.setName("테스트1");
Member mebmer2 = new Member();
member2.setId("member2");
member2.setName("테스트2");
// 엔티티 영속
EntityManager em;
em.persist(member1); // id = test1
em.persist(member2); // id = test2
1차 캐시
- 영속성 컨텍스트는 내부에 캐시(Cache)가 존재(1차 캐시)
- 영속 상태의 엔티티는 해당 캐시에 저장
- 캐시는 Map 형태로 구성되어 있으며, 키(Key)는 @Id로 매핑한 식별자이며 값(Value)는 엔티티 인스턴스
- 1차 캐시의 키는 식별자 값
- 식별자 값은 DB 기본키와 매핑
- 영속성 컨텍스트에서 데이터를 저장하고 조회하는 모든 기준은 DB 기본 키 값
엔티티 조회
Member member = em.find(Mmeber.class, "member1"); // id = member1
- 1차 캐시에서 해당 Key에 대한 엔티티가 있는지 조회
- 엔티티 조회 시 우선 1차 캐시에서 식별자 값으로 엔티티를 찾음
- 엔티티가 존재하면 DB를 조회 하지 않고, 메모리에 있는 1차 캐시에서 해당 엔티티를 조회
- 엔티티가 1차 캐시에 없다면, DB에서 조회
- 엔티티가 1차 캐시에 없으면 엔티티 매니저는 DB를 조회해서 해당 엔티티를 1차 캐시에 저장
- 1차 캐시에 저장된 후 영속성 상태의 엔티티를 반환
- 영속성 엔티티의 동일성 보장
Member m1 = em.find(Member.class, "member1");
Member m2 = em.find(Member.class, "member1");
System.out.println(a == b); // treu(동일성 보장)
엔티티 등록
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
// 데이터 변경 시 트랜잭션을 시작
transaction.begin();
em.persist(member1);
em.persist(member2);
// 여기까지는 INSERT 쿼리를 DB에 보내지 않음
// 커밋하는 순간 DB에 INSERT 쿼리를 보냄
transaction.commit();
- 트랜잭션(Transaction)을 지원하는 쓰기지연
- 엔티티 매니저는 Transaction(트랜잭션)을 커밋하기 전까지 DB에 엔티티를 저장하지 않음
- 엔티티 매니저 안에 존재하는 SQL 저장소에 INSERT SQL을 별도로 저장
- 트랜잭션이 커밋이 될 때 SQL 저장소에 있는 모든 INSERT SQL을 DB에 요청
- 플러시(flush)
- 트랜잭션이 커밋될 때 엔티티 매니저는 flush를 실행
- 트랜잭션 커밋 요청 -> 엔티티 매니저 flush 실행 -> DB에 쿼리 요청(동기화)
엔티티 수정
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
// 데이터 변경 시 트랜잭션을 시작
transaction.begin();
// 엔티티 조회(영속성)
Member m1 = em.find(Member.class, "member1");
// 엔티티 데이터 수정
m1.setName("Developer");
// 커밋하는 순간 DB에 UPDATE 쿼리를 보냄
transaction.commit();
- JPA에서는 엔티티를 수정할 때는 엔티티를 조회하여 데이터를 변경하여 저장(update() 메소드 없음)
- 변경 감지 기능을 통해 DB에 자동 반영(DB Update)
- 변경 감지는 영속성 컨텍스트(Entity Manager)가 관리하는 영속 상태의 엔티티에만 적용
- 수정 순서
- 트랜잭션 커밋 요청(엔티티 매니저 내부에서 먼저 플러시 호출)
- 엔티티 스냅샷과 비교하여 변경된 엔티티를 찾음
- 변경된 엔티티가 발견되면 Update 쿼리를 생성하여 쓰기 지연 SQL 저장소에 저장
- 다시 플러시를 호출하면서 쓰기 지연 저장소의 쿼리를 DB에 요청
- DB 커밋
- 업데이트의 기본 전략
- JPA의 기본 전략은 모든 엔티티의 필드를 업데이트하는 것이다.
- 모든 필드를 사용하면 수정 쿼리가 항상 같다.
- 동일한 쿼리를 보내면 DB는 이전에 파싱된 쿼리에 대해서는 재사용을 한다.
엔티티 삭제
EntityManager em = emf.createEntityManager();
EntityTransaction transaction = em.getTransaction();
// 데이터 변경시 트랜잭션을 시작
transaction.begin();
// 엔티티 조회(영속성)
Member member1 = em.find(Member.class, "member1");
// 엔티티 데이터 삭제
em.remove(member1);
// 커밋하는 순간 DB에 DELETE 쿼리를 보냄
transaction.commit();
- 엔티티를 삭제하기 위해서도 먼저 삭제 대상의 엔티티 조회가 필요
- DB에서 바로 삭제되는 것이 아니라, 영속성 컨텍스트(엔티티 매니저)에서만 제거
- DELETE 쿼리를 쓰기 지연 SQL 저장소에 저장.
- 트랜잭션 커밋 시 쿼리를 DB에 요청
- em.remove(member1)를 호출하는 순간, member1은 영속성 컨텍스트에서 제거되어, 더 이상 수정할 수 없다.
728x90
반응형
'개발 > Spring' 카테고리의 다른 글
연관관계 매핑의 모든 것: JPA에서 다루는 다중성, 방향성, 관계의 주인 이해 (0) | 2024.01.12 |
---|---|
JPA 엔티티 매핑 마스터하기: 기본부터 고급 전략까지 (0) | 2024.01.12 |
JPA 기초부터 실무 활용까지: Java ORM 표준의 이해 (0) | 2024.01.12 |
ORM의 이해: 데이터베이스와 객체 지향 프로그래밍의 효율적 연결 (0) | 2024.01.12 |
[JDBC, JPA] JDBC와 JPA (1) | 2023.01.04 |
댓글