# 요약

# 영속성

# 영속성 컨텍스트란?

엔티티를 영구 저장하는 환경으로 엔티티 매니저로 엔티티를 저장하거나 조회하면 엔티티 매니저는 이 컨텍스트에 엔티티를 보관하고 관리한다.

# 생명주기

  • 비영속 : 영속성 컨텍스트가 없음
  • 영속 : 영속성 컨텍스트에 저장된 상태
  • 준영속 : 영속성 컨텍스트에 저장되었다가 분리된 상태
  • 삭제 : 삭제된 상태

# 영속성 컨텍스트 특징

  • 영속된 컨텍스트는 식별자 값이 반드시 있어야 한다.
  • 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 DB에 반영함. 이를 Flush라 함.
  • 더불어 1차 캐시, 동일성 보장, 변경 감지, 지연 로딩등이 있다.

# 엔티티 Entity

# 엔티티란?

쉽게 말해 DB 테이블과 맵핑되는 존재로 JPA가 쓸 수 있게 만들어 놓은 객체라고 생각하면 된다. 세부 속성은 어노테이션을 활용하여 셋팅된다.

# 기본 키

  • 직접 할당
  • 자동 생성 (@GeneratedValue)
    • IDENTITY : 기본 키 생성을 DB에 위임
    • SEQUENCE : 데이터베이스 시퀀스 사용
    • TABLE : 키 생성 테이블

# 필드

필드와 관련된 요약은 생략함.

# 매핑

# ManyToOne

예를들어 학생과 반의 관계일 때 학생 쪽에서 반의 정보를 참조하고 싶을 때 사용하며 FK라고 생각하면 된다. @JoinColumn을 사용해 매핑해주며 이때는 @JoinColumn(name="CLASS_ID")이런 식으로 사용된다. ManyToOne에는 다음과 같은 속성이 존재한다.

  • optional : 기본값은 true이며 false일 시 연관된 엔티티가 항상 존재해야한다.
  • fetch : 참조된 엔티티를 실제로 어느 타이밍에 조회할지에 대한 셋팅이다. EAGET, LAZY가 있다.
  • cascade : 영속성 전이 기능이다. update시 참조된 엔티티를 어떻게 동작할지에 대한 설정이다.
  • targetEntity : 엔티티 타입 정보를 설정하지만 거의 사용하지 않음.

# OneToMany

ManyToOne의 반대이며 반이 학생 정보를 참조할 때 반에 소속된 학생들을 조회할 때 사용할 수 있다.

# 그외

OneToOne, ManyToMany가 존재하지만 ManyToMany는 중간 테이블을 만들어 ManyToOne으로 사용하는 것이 좋다.

# 연관관계

# 단방향 연관관계

한쪽만 값을 참조하고 있는 경우를 단방향이라고 한다. 학생과 반의 관계일 때 학생만이 반의 정보를 들고 있다면 이것든 단방향 연관관계이다.

# 양방향 연관관계

학생이 반을 참조하고 반도 학생을 참조해야할 때 잡아주는 관계를 양방향 연관관계라고 한다. 이는 DB에는 없는 개념인데 그 이유는 DB는 FK값을 한쪽만 들고 있어도 Join을 사용해서 양쪽의 값을 모두 조회할 수 있지만 객체 방식일 경우 다른 객체의 값을 참조하지 않고 있는 객체에서는 다른 객체를 알 수 있는 방법이 없다. 그래서 애플리케이션적으로 단방향을 묶어주어 사용해야한다.

위에서 이야기했듯이 양방향 연관관계는 결과적으로 단방향 연관관계를 서로 묶어 놓은 것과 같은데 이때 객체의 연관관계를 관리하는 포인트가 2개로 늘어나는 것이다. 그런데 FK는 하나지만 객체의 참조는 둘이기 때문에 이 FK를 관리할 객체를 정해야한다. 이 객체를 주인이라 부르는 것이다.

# mappedBy

주인이 아닌 객체에 사용하는 어노테이션으로 해당 어노테이션을 사용하면 객체는 FK와 관련된 로직은 오직 읽기만 가능하다.

# 주의점

사용 시 연관관계의 주인에는 값을 입력하지 않고 주인이 아닌 객체에만 데이터를 입력하는 것이다. 문제가 발생한다면 가장 먼저 확인해야할 포인트이다. 그래서 연관관계 편의 메소드를 만들어서 사용하면 더 편리하게 관리할 수 있다.

# 고급 매핑

고급 매핑과 관련된 요약은 생략함.

# 프록시와 연관관계 관리

# 프록시란?

만약에 학생 엔티티에 반의 엔티티가 참조되어있다고 했을 때 학생을 만 번 조회한다고 생각해보자. 이때 만약 반에 대한 데이터를 사용하지 않는다면 쓸데없이 자원을 낭비하게 될 것이다. 그래서 JPA는 엔티티가 실제 사용될 때 까지 DB조회를 지연하는 방법을 제공하는데 이를 지연로딩이라고 한다.(컬럼 매핑 시 사용할 수 있는 fetch속성의 사용처이다.) 그런데 지연로딩을 사용하려면 DB조회를 지연시킬 수 있는 가짜 객체가 필요하게 되는데 이를 프록시라 부른다.

# 초기화

프록시 객체는 실제 엔티티를 상속받으며 개발자가 실제로 사용할 때 DB를 조회해 실제 엔티티 객체를 생성하며 이를 초기화라고 한다.

# 프록시와 식별자

엔티티를 프록시로 조회할 때 PK를 파라미터로 전달하는데 프록시 객체는 이 PK값을 저장한다. 엔티티 접근방식을 프로퍼티로 설정했을 경우 ID를 조회했을 때 프록시를 초기화 하지 않으며 접근 방식이 필드라면 프록시 객체를 초기화 한다. 예를들면 team객체를 프록시로 설정한다음 team.getId();를 했을 때 프로퍼티 방식이면 DB조회없이 ID를 반환 받을 수 있지만 필드 방식은 DB를 조회하게 된다. 그 이유는 getId가 어떤 메소드인지 알지 못하기 때문이다. 이를 잘 사용하면 연관관계를 맺을 때 DB 접근 횟수를 줄일 수 있다. 연관관계는 FK만 해주면 되기 때문에 ID 값만 있는 프록시 객체를 넘겨주면 되기 때문이다.

# 즉시 로딩과 지연 로딩

위에서 간단하게 설명했듯이 fetch= FetchType.EAGER, fetch= FetchType.LAZY에 대한 이야기다. EAGER로 했을 경우 해당 데이터를 사용하지 않아도 무조건 조회를 한다는 것이고 LAZY는 참조된 엔티티를 사용할 때 그제서야 DB에서 조회하는 방식이다. 만약 해당 필드가 무조건 사용되는 필드라면 EAGER를 사용하는 것이 맞지만 애매한 경우거나 사용 빈도가 적다면 되도록 LAZY 사용해주는 것이 좋다. 이는 조회시 조인을 할지 말지에 대한 결정이기 때문이다.

# 영속성 전이

쉽게 말해 연관된 엔티티를 같이 영속화하는 것을 말한다. 우리가 DB에서 cascade를 거는 것과 동일하지만 이는 객체에서 동작한다는 것을 명심해야한다. 종류는 다음과 같다.

  • ALL
  • PERSIST
    • persist, remove를 실행할 때 전이되지 않고 flush를 할 때 전이된다.
  • MERGE
  • REMOVE
    • persist, remove를 실행할 때 전이되지 않고 flush를 할 때 전이된다.
  • REFRESH
  • DETACH

# 값타입

JPA는 컬럼의 타입을 Java의 기본 타입 이외에 커스텀하게 지원하기도 한다. 예를 들면 지역 + 주소 + 우편번호를 합친 타입을 지원하는데 이때 등장하는 어노테이션이 @Embadded, @Embaddable이다. @Embadded은 커스텀 타입을 사용하는 컬럼이라는 뜻이고 @Embaddable는 커스텀 타입을 선언하고 정리해놓은 클래스에 사용하면 된다.

나머지 내용은 생략.

# 객체지향 쿼리 언어

JPA에서 사용할 수 있는 SQL언어는 JPQL, Criteria, QueryDSL, Native SQL이 있으나 스프링 데이터 프로젝트가 공식적으로 QueryDSL을 지원하고 있기 때문에 QueryDSL에 대해서 간략하게 서술함

# QueryDSL

쿼리를 짤 때 함수를 사용하는 것처럼 쉽게 사용할 수 있다.

List<Item> list = query.from(item)
    .where(item.name.eq("HOT").and(item.price.gt(20000)))
    .list(item);

또 Criteria 사용하지 못하는 and, or절을 where절에서 사용할 수 있다.