참고 이글은 자바 ORM 표준 JPA프로그래밍을 읽고 정리한 글입니다.
영속성 컨텍스트란?
엔티티를 영속화하고 관리하는 환경.
엔티티 매니저는 영속성 컨텍스트에 엔티티를 관리한다.
엔티티 생명주기
1.비영속 : 영속성 컨텍스트와 연관X
2.영속 : 영속성 켄텍스트에 저장된 상태
3.준영속 : 영속성 컨텍스트안에서 분리된상태
4.삭제 : 삭제된 상태
-비영속
객체가 만들어져있지만 아직까지 DB에 전혀 관련이 없는 상태.
-영속
엔티티 매니저를 통해서 관리를 받고 있는 상태. create,find,update모두 이러한 상태.
-준영속
영속성 컨텍스트가 관리하던 영속상태의 엔티티가 더이상 관리를 받지 않으면 이러한 상태.
close(),clear(),detch() 함수로 이러한 상태를 만든다.
-삭제
remove()로 데이터베이스에 삭제된 상태.
영속성 컨텍스트의 특징
-엔티티를 식별자 값(db에서의 primary key)으로 구분. 식별자 값 없을시 예외발생.
-실제로 DB에 저장되는 것은 트랜잭션을 커밋하는 순간 저장됨. => 플러시
-장점
:1차캐시
:동일성보장
:트랜잭션을 지원하는 쓰기 지연
:변경 감지
:지연 로딩
엔티티 조회
1차 캐시 :영속성 컨텍스트 내부에 가지고 있는 캐시. 영속상태의 엔티티는 모두 이곳에 저장.
1차 캐시의 키:식별자 값
엔티티 조회 방법 : 1차 캐시에서 탐색 후 값이 없을 시 DB 조회. = > 앞전에 얘기한 비교의 문제 해결.
엔티티 등록
persist(member)와 같이 엔티티를 등록할경우 바로 DB에 등록이 되는 것이 아니다. 트랜잭션이 커밋을 하기 전까지는 영속 컨텍스트 내부에 있는 쓰기 지연 저장소란 곳에 등록할 SQL문을 차곡차곡 쌓아둔다. 그리고 트랜잭션이 커밋을 하면 쿼리를 DB로 보낸다. 이것을 트랙잭션을 지원하는 쓰기 지연이라고 한다.
실제로 트랜잭션 범위안에서 실행되기때문에 바로 DB에 등록 쿼리를 보내는 거나 SQL저장소에 모앗다가 커밋에 보내는 거나 실제로 커밋을 해야만 등록되기때문에 트랙잭션을 지원하는 쓰기지연을 사용한다.
엔티티 수정
엔티티의 수정은 따로 update같은 것이 없고 값만 바꾸면 바로 바뀐다고 했다. 왜 그렇게 되는 것일까? jpa에는 엔티티의 변경사항을 데이터베이스에 자동으로 반영하는 기능인 변경감지를 지원한다.
스냅샷:엔티티를 영속성 컨텍스트에 보관할때 최초 상태를 복사해서 저장.
우리는 이 스냅샷과 플러시 시점에서 엔티티를 비교해서 변경된 엔티티를 찾는다.
변경감지가 일어나는 순서는 다음과 같다.
1.트랜잭션을 커밋하면 엔티티 내에서 플러시가 발생.
2.엔티티와 스냅샷을 비교해서 변경된 엔티티 찾음
3.변경된 엔티티가 있으면 수정쿼리를 생성해서 쓰기 지연 저장소로 보냄
4.쓰기 지연 저장소의 SQL을 데이터베이스에 보낸다.
5.DB 트랜잭션을 커밋.
변경감지는 영속성 컨텍스트가 관리하는 영속 상태의 엔티티에만 적용된다.
Update가 일어날때 바뀐 필드의 값만 바꾸는 것이 아니라 모든 필드를 가져와 바뀐부분과 바꾼후 모든 필드를 업데이트 한다. -> JPA기본전략.
WHY?
-모든 필드를 가져와서 업데이트하면 수정쿼리 길이가 늘 같다. -> 애플리케이션 로딩 시점에 수정 쿼리를 미리 생성하고 재사용 가능
-데이터베이스에 동일한 쿼리를 보내면 데이터베이스는 이전에 한 번 파싱된 쿼리 재사용 X
엔티티 삭제
삭제 또한 등록과 비슷하게 삭제 쿼리는 쓰기지연 저장소에 등록한다. 이후 커밋을 해야 플러쉬가 호출대고 실제 DB에삭제쿼리가 전달된다. 영속성 컨텍스트에는 remove함수를 호출한 순간부터 제거된다.
플러시
영속성 컨텍스트 변경 내용을 DB에 반영
-플러시가 실행하면 일어나는일
1.변경 감지가 동작해서 스냅샷과 비교해서 수정된 엔티티를 찾고, 수정내용을 담은 수정쿼리를 쓰기지연 공간으로 보낸다.
2.쓰기지연 저장소의 쿼리를 DB에 전송.
-플러시 호출방법
1.직접호출
flush()메소드를 직접 호출해서 강제로 플러쉬. 거의 사용X
2.트랜잭션 커밋 시 자동 호출
DB에 변경된 내용을 바꾸지 않고 커밋이 된다면 어떤 데이터도 DB에 반영되지 않는다. 따라서 트랜잭션을 커밋할경우 자동으로 플러쉬를 호출한다.
3.객체지향 쿼리 실행시 자동호출
JPQL 같은 객체지향 쿼리를 호출할때도 플러시가 자동으로 실행된다.
지금까지 엔티티의 비영속 -> 영속 -> 삭제 상태변화를 보았다. 이제 영속 ->준영속의 상태 변화를 보자.
detatch() :엔티티를 준영속 상태로 전환
만약 persist(member)로 영속화한다음 곧바로 detatch()를 하면 준영속 상태가 된다. 준영속 상태가 되면 1차캐시와 쓰기지연 저장소에 이 엔티티와 관련한 모든 정보가 제거된다. persist를 했을때 등록 쿼리가 쓰기지연 저장소에 들어갔지만 커밋을 하기전이엇였기에 detatch()로 인해 등록 쿼리가 날라가서 실제 db에는 데이터가 저장되지 않는다.
즉 준영속 상태는 영속성 컨텐스트로부터 분리되어 어떠한 기능도 받지 못하는 상태이다.
clear():영속성 컨텍스트 초기화
detatch()가 하나의 엔티티를 준영속 상태로 바꾸는 것이라면 clear()는 영속성 컨텍스트 자체를 초기화해서 모든 엔티티를 준영속 상태로 만든다.
close() : 영속성 컨텍스트 종료
영속성 컨텍스트를 종료하면 관리하던 모든 엔티티들이 준영속 상태로 바뀌게된다.
자 그렇다면 이렇게 준영속 상태가 되면 어떠한 특징을 가지게 될까?
준영속 상태 특징
1.비영속 상태에 가까움 -> 영속성컨텍스트가 지원하는 1차 캐시,쓰기지연,변경감지,지연로딩을 포함한 어떠한 기능도 제공받지 못함
2.식별자 값을 가짐 -> 영속상태에서 식별자 값을 가지고있었기에 준영속 상태가 되도 여전히 가지고 있다.
3.지연로딩을 할 수 없다 -> 영속성 컨텍스트가 더는 관리하지않기에 지연로딩시 에러.
지연로딩 : 실제 객체 대신 프록시 객체를 로딩해두고 해당 객체를 실제 사용할 때 영속성 컨텍스트를 통해 데이터를 불러오는 방법.
merge():병합
자 그럼 이제 이렇게 준영속 상태의 엔티티를 다시 영속 상태로 바꾸기 위해서는 merge()를 사용해야 한다.
또한 비영속 앤티티도 영속 상태로 만들 수 있다.
-병합 작동방식
1.파라미터로 넘어온 엔티티의 식별자 값으로 영속성 컨텍스트 조회
2.엔티티가 없으면 DB에 조회
3.DB에도 없으면 새로운 엔티티를 생성해서 병합.
즉 merge()는 준영속인지 비영속인지 고려하지 않고 조회가 가능하면 조회해서 병합하고 조회를 못하면 새로 생성해서 병합을 한다.
'Jpa' 카테고리의 다른 글
고급매핑 (0) | 2021.01.10 |
---|---|
다양한 연관관계 매핑 (0) | 2021.01.10 |
연관관계 기초 매핑 (0) | 2021.01.09 |
엔티티 매핑 (0) | 2021.01.09 |
JPA란? (0) | 2021.01.06 |