나다.
이 글이 뭐하는 글이냐면
이번 글은 JPA의 영속성 컨텍스트에 대해 설명하기 위해 작성한다.
무릇 JPA를 배우기 시작하며 가장 처음 접하는 단어가 "영속성 컨텍스트" 이지 않나 싶다.
그 만큼 영속성 컨텍스트란 JPA의 핵심적인 부분이라 볼 수 있는 부분이다.
영속성 컨텍스트와 친구들
영속성 컨텍스트에 대해 알기 전 먼저 알아야 할 친구가 남아있다.
Entity(엔티티)와 EntityManager(엔티티 매니저)
간단하게 설명하면
엔티티는 테이블과 연결될 객체
엔티티 매니저는 그 객체를 영속성 컨텍스트에 보관하거나 조회하는 등
사용자가 원하는 액션을 취한다.
그렇다면 오늘의 주제인 "영속성 컨텍스트"란 무엇인가.
영속성 컨텍스트란 당신과 데이터베이스 사이에 객체를 보관하기 위한 "임의의 공간"을
지칭하는 말이다.
어플리케이션 <ㅡ> 영속성 컨텍스트(JPA) <ㅡ> 데이터베이스
다음과 같은 구조로 볼 수 있겠다.
이 영속성 컨텍스트를 통해 엔티티 매니저는 엔티티의 관리를 실행한다.(등록 수정 삭제 등)
영속성 컨텍스트에 어떤 엔티티 객체를 저장하고 싶다면.
@Entity
@Getter @Setter
public class Member {
@Id //해당 테이블의 PK임을 의미.
@GeneratedValue // MariaDB or MySQL같은 경우 Auto increment, Oracle의 경우 Sequence의 사용을 의미.
private Long id;
private String name;
protected Member() {
}
public static Member createMember(String name) {
Member member = new Member();
member.setName(name);
return member;
}
}
먼저 저장할 수 있는 엔티티 클래스를 만들어야 한다.
PK와 Auto increment 또는 Sequence가 뭔지 모른다고 한다면 지금 이 글 뿐만 아닌 JPA 자체를 봐야 소용이 없기때문에
기본적인 데이터베이스를 공부하고 더 보는 것을 추천드린다.
기본 생성자가 protected인 것은 JPA가 허용하기 때문에 그렇게 쓴 것이다.
기본 생성자를 protected로 막아놓고
static 메소드를 통해 외부의 객체 생성을 파라미터로 제한함으로
꼬임을 방지할 수 있다는 이점이 있는데 이건 나중 글에서 설명하겠다.
객체를 생성했다면 저장하는 것은 간단하다.
@Repository
@RequiredArgsConstructor
public class MemberRepository {
private final EntityManager em;
public Member save(Member member) {
em.persist(member);
return member;
}
}
em.persist(객체); 라는 문법을 통해 객체를 영속성 컨텍스트에 저장 할 수 있다.
영속 컨텐츠의 상태구분
생명주기라는 말을 들어 본 적이 있는가. 아마 많은 곳에서 쓰이는 단어일 것이다.
엔티티 또한 생명주기를 가지고 있다.
첫번째로 "비영속 상태"다.
비영속 상태란 현재 엔티티 객체를 생성했지만 아직 영속성 컨텍스트와 무관한 상태를 말한다.
Member member = Member.createMember("abc");
Member라는 객체가 생성된 것은 맞지만 JPA / 영속성 컨텍스트와 아무런 접점이 없는 상태다.
쉽게말해 나와 내가 좋아하는 여자아이들의 미연씨의 상태라고 생각하면 된다.
나(객체) 세상에 생성됨. 근데 미연씨(영속 컨텍스트)와 만난 적도 아는 사이도 아무것도 아님.
씨X. 슬프다.
어쨋는 비영속이란 나와 당신 그리고 연예인의 관계와 같다고 생각하면 쉽게 이해할 수 있다.
아무런 상관이 없는 상태라는 뜻 이다.
다음은 "영속" 상태다.
영속상태란
public void save(Member member) {
em.persist(member);
}
다음과 같은 명령을 통해 member라는 객체를 영속 컨텍스트에 등록하고 관리하기 시작하는 순간부터의 상태를 이야기 한다.
그냥 영속 컨텍스트 안에 들어앉아 있는 상태다.
JPA가 관리하는 중인 대상이다.
라고 이해하시면 된다.
em.persist 하면 데이터베이스에도 같이 꽂힌다. 이건 flush(플러쉬)라는건데 이건 다음 글에서 자세히 다룸.
다음은 "준영속" 상태다.
준영속 상태란 한번 영속성 컨텍스트에 들어갔다 나온 상태를 말한다.
수건을 예로 들겠다.
수건을 물에 담궜다빼면 그 수건은 말라있는가 젖어있는가.
수건이 말라있다면 호그와트에서 잡아가기 전에 자진출두 하시길 바란다.
어쨋든 한번 담궜다 뺀 수건은 여전히 젖어있듯
한 번 영속성 컨텍스트에 들어갔다 나온 객체는 "식별자 값"을 가지고있다.
이 식별자 값이란 것은 아까 우리가 봤던
@Id //해당 테이블의 PK임을 의미.
@GeneratedValue // MariaDB or MySQL같은 경우 Auto increment, Oracle의 경우 Sequence의 사용을 의미.
private Long id;
이거다.
기본적으로 Auto increment와 Sequence는 컬럼 값이 추가될 때 마다 1부터 순차적으로 늘어난다.
고유식별자로서 얼마나 좋은 구조인가.
결론적으로 em.persist로 저장되는 엔티티 객체는 고유 아이디가 부여되어 있고 그 고유 아이디로
영속성 컨텍스트에서 조회까지 이루어지게 된다.
어쨋든, 영속성 컨텍스트가 관리하던 대상에서 제외된 엔티티를 준영속 상태라고 한다.
엔티티를 준영속 상태로 만드는 방법은
public void makeDetach(Member member){
em.detach(member);
}
// 특정 객체 하나를 준영속 엔티티로 만듦.
public void clearPc() {
em.clear();
}
// 영속성 컨텍스트를 비움으로 영속 엔티티는 모두 준영속 엔티티로 전환됨.
public void closePc() {
em.close();
}
// 영속성 컨텍스트를 닫음으로 영속 엔티티는 모두 준영속 엔티티로 전환됨.
세 가지가 있다.
그리고 마지막으로 무(無)로 되돌리는 "삭제"
public void removeEntity(Member member){
em.remove(member);
}
완전히 영속 컨텍스트와 데이터베이스에서 삭제시킨다.
여기까진 안 어려움.
여기까진 어렵지 않게 이해할 수 있다.
다만, 이 다음 글부터 올리게 될 flush와 1차 캐시, 더티 체킹 등 실질적으로 데이터에 손을 대는
동작들에 대해 배우기 시작하는 순간부터 별에 별 개X같은 기현상들이 발생하기 시작한다.
전설의 고향을 보는 느낌도 살짝 들었음.
다음 글에서는 실제적으로 저장하는 동작이 이루어지는 flush와 기타 등등 친구들에 대해
알아보겠다.
혹시나 글에 틀린 점이 있더라도 그건 내가 허접이라 그런 것이니 너른 양해를 부탁드린다.
그럼 컴파일 오류 없는 개발 하시길. :)
'JPA' 카테고리의 다른 글
[JPA] no entitymanager with actual transaction available for current thread (5) | 2023.01.04 |
---|---|
[JPA] 연관관계 맵핑(다대일 / N:1) (2) | 2022.12.28 |
[JPA] JPA와 PK 그리고 Id (1) | 2022.12.28 |
[JPA] 영속성 컨텍스트와 Flush (4) | 2022.12.22 |
[JPA] JPA란 무엇인가. (1) | 2022.12.20 |