<TIL> 39. 영속성 컨텍스트, JPA 엔티티

YUJIN LEE·2023년 3월 3일
0

개발log

목록 보기
34/149

영속성 컨텍스트

엔티티를 영구 저장하는 환경
어플리케이션이 DB에서 꺼내온 데이터 객체를 보관하는 역할.
영속성 컨텍스트는 엔티티 매니저를 통해 엔티티를 조회하거나 저장할때 엔티티를 보관, 관리

JPA 엔티티 상태

비영속(New)

  • 영속성 컨텍스트와 관계가 없는 새로운 상태.
    해당 객체의 데이터가 변경되거나 말거나 실제 DB의 데이터와는 관련x, 그냥 자바 객체인 상태

영속(Managed)

  • 엔티티 매니저를 통해 엔티티가 영속성 컨텍스트에 저장되어 관리되고 있는 상태
    이와같은 경우 데이터의 생성, 변경 등을 JPA가 추적하며 필요하면 DB에 반영

준영속(Detached)

  • 영속성 컨택스트에서 관리되다가 분리된 상태

삭제(Removed)

  • 영속성 컨택스트에서 삭제된 상태

영속성 컨텍스트의 설계 이유?

  • 1차 캐시?
    DB를 이용하는 작업은 상대적으로 부하와 비용이 심한 작업.
    그래서 부하가 심한 작업을 자주 하는것을 줄여야 함.

1차캐시를 둔다면?
1. find("memberB")와 같은 로직이 있을 때 먼저 1차 캐시 조회
2. 있으면 해당 데이터 반환
3. 없으면 그 때 실제 DB로 "SELECT * FROM..."의 쿼리를 내보냄
4. 그리고 반환하기 전에 1차 캐시에 저장 후 반환
-> memberB를 find하는 요청이 다시 들어와도 굳이 DB로 가지 않아도 됨.

  • 쓰기 지연 SQL 저장소?
  1. memberA, memberB 영속화
  2. entityManager.commit() 메서드 호출
  3. 내부적으로 쓰기 지연 SQL 저장소에서 Flush가 일어남
  4. "INSERT A", "INSERT B"와 같은 쓰기 전용 쿼리들이 DB로 흘러감
  • DirtyChecking을 통해 데이터의 변경을 감지해 자동 수정.
  • JPA는 1차 캐시와 쓰기지연 SQL 저장소를 이용해 변경과 수정 감지
  1. 1차 캐시에는 DB의 엔티티 정보와 해당 엔티티를 조회한 시점의 데이터 정보를 같이 저장.
  2. 엔티티 객체와 조회 시점의 데이터가 다르다면 변경이 발생한걸 알 수 있음
  3. 해당 변경 부분을 반영할 수 있게 UPDATE 쿼리 작성

기본 엔티티 관련 어노테이션

@Entity 관련
1. 기본 생성자는 필수.
2. final 클래스, enum, interface 등에는 사용 불가
3. 저장할 필드라면 final을 사용하면 안된다.

@Table 관련

  • 엔티티와 매핑할 테이블의 이름. 생략시? 매핑한 엔티티 이름을 테이블 이름으로 사용.

@Column 관련
1. 객체 필드를 테이블 컬럼에 매핑하는데 사용
2. 생략 가능
3. 속성들은 자주 쓸 일이 없고, 보통 생략도 한다.

@Enumerated 관련
1. Java Enum을 테이블에서 사용한다고 생각하면 좋다.
2. 속성으로는 Ordinal, String.
String - 해당 문자열 그대로 저장해 비용이 많이 들지만, 나중에 Enum이 변경되어도 위험할 일이 없어 일반적으로 String 많이 사용

연관관계 관련 심화

단방향 연관관계

@ManyToOne

  • 이름 그대로 다대일(N:1) 관계라는 매핑 정보.
    "한명의 유저가 여러개의 주문"
    주요속성 - optional, fetch, cascade
    optional - false로 설정하면 항상 연관된 엔티티가 있어야 생성할 수 있다는 뜻

@JoinColumn(name="food_id")

  • 외래 키를 매핑시 사용
    (실제 DB에는 객체 필드에 해당 객체 테이블의 외래키가 들어감)
    기본적으로 @Column이 가지고 있는 필드 매핑관련 옵션 설정들과, 외래키 관련 몇 옵션이 추가된 옵션

양방향 연관관계

DB의 외래키는 양방향에서 조회 가능

외래키는 연관관계가 있는 두개의 테이블 중 하나의 테이블만 있으면 충분.
두 객체 연관관계 중 하나를 정해 테이블의 외래키 관리 -> 연관관계의 주인
연관관계의 주인만이 DB 연관관계와 매핑되고 외래키를 관리(등록, 수정, 삭제)하게 되어있음.
반면, 주인이 아닌 쪽은 읽기만 할 수 있다.
연관관계의 주인을 정한다는 것은 외래키 관계자를 선택하는 것.

  • 연관관계의 주인에 의해 mappedBy된다.

양방향 연관관계의 주의점

연관관계의 주인에는 값을 입력하지 않고, 주인이 아닌 곳에만 값을 입력하면 문제

객체 관점에서 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전.
양쪽 방향 모두 값을 입력하지 않으면 JPA를 사용하지 않는 순수한 객체 상태에서 심각한 문제 발생.

프록시


엔티티를 조회시 연관된 엔티티들이 항상 사용 x
JPA는 필요없는 DB조회를 줄이며 성능을 최적화.
이런 문제를 해결하려고 엔티티가 실제 사용될 때 까지 DB 조회를 지연하는 방법을 제공
-> 지연로딩
지연로딩 기능을 사용하려면 실제 엔티티 객체 대상에 DB 조회를 지연할 수 있는 가짜 객체가 필요한데, 이걸 프록시 객체라고한다.

즉시로딩

엔티티를 조회할 때 연관된 엔티티도 함께 조회
@ManyToOne(fetch = FetchType.EAGER)

지연로딩

연관된 엔티티를 실제 사용할 때 조회한다
@ManyToOne(getch = FetchType.LAZY)

기본적으로 "즉시로딩"은 연관된 엔티티를 조인해 다 긁어온다
"지연로딩"은 실제로 가짜 객체를 이용시, 그때 별도의 쿼리가 나간다..

즉시로딩은 연관관계가 많고 복잡할수록 비용이 기하급수적으로 늘어나 지연로딩을 걸어두는게 일반적!

기본값

@ManyToOne, @OneToOne : 즉시 로딩(FetchType.EAGER)
@OneToMany, @ManyToMany : 지연 로딩(FetchType.LAZY)

그렇다면 굳이 필요가 없다면, 앞으로 코딩시
@ManyToOne(FetchType.Lazy)로 걸어주는게 좋다...

영속성 전이

특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶으면 영속성 전이기능을 사용하면 된다.
JPA는 cascade 옵션으로 영속성 전이를 제공

@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
private List

addresses;

profile
인정받는 개발자가 되고싶습니다.

0개의 댓글