[스프링(spring)]영속성 컨텍스트

allnight5·2022년 12월 7일
0

스프링

목록 보기
5/62

참조
참조사이트1
참조사이트2
참조사이트3

영속성(persistency)이란 데이터를 영구적으로 저장하는 것을 의미합니다.

따라서 영속성 컨텍스트란 직역하자면 데이터를 영구적으로 저장하는 환경 정도로 해석될 수 있습니다.
영속성 컨텍스트 란? entity를 영구 저장하는 환경입니다
DB에 있는 데이터를 SELECT 해서 영속성 컨텍스트에 넣는 것 : 영속화
데이터 베이스에 넣을때 save는 영속성 컨텍스트에 넣어서 insert하지만
saveFlush는 바로 insert문을 실행한다.

JPA가 필요한 이유

기본적으로 JPA는 객체지향 언어인 JAVA와 Database 사이의 패러다임 불일치를 해결하기 위해서 도입된 규약입니다.
1. 객체로 되어있는 Java의 코드를 바로 Database에 적용할 수 없습니다.
2. Database에 직접적으로 Update를 진행하게 되면 수정 중 오류가 발생하였을 때 데이터베이스의 정보가 원하는 방향으로 모두 수정이 이루어지지 않거나, Database의 정보들이 손상될 수 있습니다.
그래서 1번을 해결하기 위해서 JPA를 이용하여 Query로 java문을 번역한뒤 Database와 정보를 주고 받는 행위를 합니다.
그런데 이 JPA는 영속성 컨텍스트(Persistence Context)를 이용합니다.

영속성 컨텍스트란?

엔티티를 영구 저장하는 환경이라는 뜻
아래의 코드와 같이 엔티티 매니저를 통해서 영속성 컨텍스트에 접근할 수 있다.
EntityManager entityManager = new EntityManager();
entityManager.persist(entity)


비영속(new/transient)
영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
//객체를 생성한상태(비영속)
TestClass testClass = new TestClass();
testClass.setId("member1");
testClass.setUsername("회원1");


영속(managed)
영속성 컨텍스트에 관리되는 상태
//객체를 저장한 상태(영속)
entityManager.persist(testClass);


준영속(detached)
영속성 컨텍스트에 저장되었다가 분리된 상태
//영속성 컨텍스트에서분리, 준영속 상태
entityManager.detach(testClass);: 특정 엔티티만 준영속 상태로 전환
entityManager.clear();: 영속성 컨텍스트를 완전히 초기화
entityManager.close();: 영속성 컨텍스트를 종료

영속 -> 준영속
영속 상태의 엔티티가 영속성 컨텍스트에서 분리(detached)
영속성 컨텍스트가 제공하는 기능을 사용 못함


삭제(removed)
삭제된 상태
entityManager.remove(testClass);


즉 처음에 객체가 생성된 상태 -> 비영속
영속성 컨텍스트에 데이터가 저장된 상태 -> 영속
영속성 컨텍스트에 저장된 데이터가 분리된 상태 -> 준영속
마지막으로 삭제된 상태 -> 삭제

영속성 컨텍스트의 이점

1차 캐시

  • key는 pk, value는 entity 입니다
  • 영속성 컨텍스트의 내부적으로 1차 캐시가 존재하며 1차캐시에서 가져오기때문에 쿼리가 발생하지 않습니다
  • 1차 캐시는 Map<Key(primary key), Value(Entity)> 형태로 저장합니다.
    이렇게 되면, DB에 직접 조회를 요청하지 않아도 캐시에서 바로 조회가 가능하다는 이점이 있습니다. 존재하지 않는다면, DB에서 조회하여 캐시에 저장하고, 저장되어 있는 동안에는 빠른 조회가 가능합니다.
  • 순서
    1.1차캐시에서 데이터를 찾습니다
    2.1차 캐시에 없으면 디비에서 조회합니다
    3.가져온 데이터를 1차캐시에 저장 하고 반환합니다

2. 동일성(identity) 보장

반복가능한 일기(Reapeatable read) 등급의 트랜잭션 격리 수준을 데이터베이스가 아닌 어플리케이션 차원에서 제공합니다 격리성 레벨 4단계중 3단계 수준을 제공한다는 말입니다.

Member a = em.find(Member.calss, "member1" );
Member b = em.find(Member.calss, "member1" );

3. 트랜잭션을 지원하는 쓰기 지연(transactional write-behind)

transaction이 시작되는 시점부터 끝나는 시점까지 저장소에 SQL을 모아 두고,
transaction이 종료되는 시점에 transaction.commit()이 호출됨과 동시에 모아둔 쿼리를 모두 보냅니다.

tx.begin();	: 트랜잭션 시작

.
em.persist(memberA);
em.persist(memberA);
// 여기까지는 insert sql을 데이터베이스에 보내지 않는다.
.
// 커밋하는 순간 데이터베이스에 insert sql을 보낸다.
tx.commit(); : 트랜잭션 커밋

4. 변경 감지(dirty checking)

em.find(entity)로 가져와 영속성 컨텍스트에 저장된 엔티티는 변경이 일어나면 자동으로 수정 됩니다 1차 캐시에 있는 스냅샷 필드와 비교하여 변경된 부분을 확인합니다
: flush()가 호출되는 시점에 Entity와 스냅샷을 전부 비교 후 변경이 된 것을 감지 ( Dirty Checking ) 한 후에 update 쿼리를 작성 후, update 쿼리를 보낸다.

// 엔티티 조회
Member memberA =em.find(Member.class, "memberA");
.
memberA.setUsernae("hello");
memberA.setAge(10);
.
// em.update(member); // update가 필요할 것처럼 보이지만 JPA가 알아서 비교해서 update 쿼리를 작성해준다.

tx:commit(); : 커밋

플러시

: 영속성 컨텍스트의 변경 내용을 DB에 반영

  • 플러시 발생

    • 변경 감지
    • 수정된 엔티티 쓰기 지연 SQL저장소에 등록
    • 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 전송
  • 영속 컨텍스트를 플러시 하는 방법

    • em.flush() : 직접 호출
    • 트랜잭션 커밋 : 플러시 자동 호출
    • JPQL 쿼리 실행 : 플러시 자동 호출

영속성 컨텍스트를 비우지 않음
영속성 컨텍스트의 변경내용을 데이터베이스에 동기화
트랜잭션이라는 작업 단위가 중요 -> 커밋 직전에만 동기화하면 됨

profile
공부기록하기

0개의 댓글