JPA 소개 및 엔티티 매핑

Song Chae Won·2023년 5월 18일
0

스프링부트와 AWS

목록 보기
16/20
post-thumbnail

2023-05-16 EFUB 7주차 세션을 듣고 정리한 내용입니다.

JPA란?

https://velog.io/@chhaewxn/%EC%9E%90%EB%B0%94-ORM-%ED%91%9C%EC%A4%80-JPA-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-JPA-%EC%86%8C%EA%B0%9C
앞의 포스팅 내용 참조 😊

JPA 엔티티 매핑

@Entity

  • 생략할 수 없는 필수 어노테이션
  • JPA는 @Entity가 설정된 클래스로부터 생성된 객체만 엔티티로 인지하고 사용할 수 있다.
    ➡️ @Entity를 일반 자바 객체와 구분하기 위한 어노테이션으로 이해해도 된다.
  • 엔티티 클래스는 다른 엔티티 클래스와 구분하기 위한 유일한 엔티티 이름을 가지고 있어야 한다.

@Table

  • 엔티티 이름과 테이블 이름이 일치하지 않는 경우 이 어노테이션을 이용하여 매핑할 테이블 이름을 지정해야 한다.
  • 다양한 속성
    - name: 매핑할 테이블 이름을 지정
    - catalog: 데이터베이스 카탈로그를 지정
    - schema: 데이터베이스 스키마를 지정
    - uniqueConstraints: 결합 unique 제약 조건을 지정하며, 여러 개의 칼럼이 결합되어 유일성을 보장해야 하
    는 경우 사용

@Column

  • 엔티티 클래스의 멤버변수와 테이블 칼럼을 매핑할 때 사용
  • 지원하는 속성은 다양하지만 name, nullable 정도를 주로 사용
  • @Column(unique = true, length = 10) 테이블의 name 속성을 바꾸는 것은 런타임에 영향을 주지만, unique나 nullable 등의 제약 조건 설정은 JPA의 실행 로직에는 영향을 주지 않고 단순히 DDL을 생성하는 데에만 영향을 준다.

@Enumerate

  • DB에는 enum 타입이 없지만, @Enumerated를 사용하면 된다.
  • 자바 Enum 타입을 매핑할 때 사용한다.
  • 속성으로는 ORDINAL과 STRING이 있다.
    - ORDINAL(기본값) : enum 순서를 DB에 저장(Integer로 저장된다.)
    - STRING : enum 이름을 DB에 저장
  • ORDINAL을 사용하면 안된다!
    USER랑 ADMIN만 가지고 있다가, 앞에 GUEST를 추가했다면?
    기존에 0, 1이었던 USER와 ADMIN이 1, 2로 변경되는데,
    기존의 데이터는 당시 저장된 숫자로 저장되어 있어 에러 발생

@Temporal

  • 날짜 타입을 매핑할 때 사용
  • 옛날에는 필요했지만 지금은 필요 없다
  • 최신 하이버네이트에서는 그냥 LocalDate나 LocalDateTime을 사용
  • LocalDate는 date, LocalDateTime는 timestamp로 DB에 각각 저장된다
    - Date : 2013-10-11
    - Time : 11:11:11
    - Timestamp : 2013-10-11 11:11:11

@Lob

  • 데이터베이스 BLOB, CLOB 타입과 매핑
  • @Lob에는 지정할 수 있는 속성이 없다
  • 매핑하는 필드 타입이 문자면 CLOB, 나머지는 BLOB으로 매핑
  • CLOB : String, char[], java.sql.CLOB
  • BLOB : byte[], javasql.BLOB

@Transient

  • 필드 매핑 X
  • 데이터베이스에 저장 X, 조회 X
  • 주로 메모리상에서만 임시로 어떤 값을 보관하고 싶을 때 사용

Table & Column Naming

  • 예약어: 주문을 나타내는 Order 의 경우 예약어를 피하기 위해 객체는 Order로 table은 Orders 로 나타내는게 관례이다.
  • Table 네이밍: 소문자의 underscore (snake_case) 가 일반적이다.
  • Entity의 id: 객체의 필드는 id 라고 만들고 @Column(name = "member_id") 이런 식으로 만드는 것이 좋다.
  • 객체와 Table의 매핑: Hibernate 의 기존 구현에서는 Entity의 필드명을 그대로 테이블의 필드명으로 적지만, springboot 사용 시 SpringPhysicalNamingStrategy 를 사용해서 필드명의 기본 전략이 camelCase ➡️ snakecase 이고, 대문자를 소문자로, '.' 을 '' 로 변경한다. (커스텀한 테이블 네이밍을 하고 싶은 경우에도 변경
    해서 활용 가능하다

식별자 값 자동 생성

JPA는 엔티티 클래스로부터 생성된 엔티티를 기반으로 데이터 영속성을 관리한다.
따라서 엔티티 클래스를 데이터 베이스 테이블과 어떻게 매핑하느냐가 JPA의 핵심이자 전부다.

  • 직접 할당: 기본 키를 애플리케이션에서 직접 할당 @Id
  • 자동 생성: 대리 키 사용 방식
    - IDENTITY 전략
    - SEQUENCE 전략
    - TABLE 전략
    - 자동 전략
  • 복합 키 사용하기 ➡️ 두 개 이상의 칼럼을 결합하여 키로 사용하는 방식. @Embeddable 가 붙은 식별자 전용 클래스 생성)

IDENTITY 전략

  • 주로 MySQL이나 DB2같은 데이터베이스에서 사용하며 키 생성에 대한 처리를 전적으로 데이터베이스에게 위임
  • 동작원리 : EntityManager의 persist 메소드가 호출되는 순간 Insert 구문이 생성되어 데이터베이스에 전송
  • 데이터베이스에서 IDENTITY 전략으로 키를 생성한 후 엔티티 클래스의 식별자 변수에 할당함
  • 데이터가 추가된 것을 확인하려면 transaction의 commit 메소드가 호출 된 후 확인 가능

SEQUENCE 전략

  • 아이덴티티 전략과 사용방법은 거의 유사하지만 유일키를 생성하기 위해 시퀀스라는 별도의 오브젝트를 사용
    하는 점에서 아이덴티티 전략과 차이가 있다. (오라클, PostgreSQL, DB2, H2에서 사용 가능)

TABLE 전략

  • IDENTITY, SEQUENCE 전략은 데이터베이스에서 해당 기능을 지원해야 사용가능 하지만 JPA는 특정 데이
    터베이스에 종속되지 않은 영속성 관리를 지향한다. ➡️ 데이터베이스에 종속되지 않은 전략이 필요
  • 데이터베이스에 종속되지 않으며 별도의 식별자 테이블을 생성하여 식별값을 관리

자동 전략

  • 데이터베이스가 확정되지 않은 상태에서 데이터베이스 연동 처리해야 하는 경우,
  • 프로젝트 수행하는 도중에 데이터베이스가 변경되는 경우에 효율적
  • 오라클을 선택하면 SEQUENCE를, MySQL을 선택하면 IDENTITY를 사용

연관관계 매핑

방향성

  • 단방향: 회원과 팀이 있을 때 (개발자 -> 프로젝트), (프로젝트 -> 개발자) 둘 중 한쪽만 참조하는 것
  • 양방향: (개발자 -> 프로젝트), (프로젝트 -> 개발자) 모두 서로 참조하는 것

매핑의 종류

  • 일대일 @OneToOne
  • 일대다 @OneToMany
  • 다대일 @ManyToOne
  • 다대다 @ManyToMany

양방향 매핑의 규칙: 연관관계의 주인

  • 객체의 두 관계 중 하나를 연관관계의 주인으로 지정한다.
  • 연관관계의 주인만이 외래 키를 관리(등록, 수정, 삭제)할 수 있다.
  • 주인이 아닌 쪽은 읽기만 가능하다.
  • 주인이 아니면 mappedBy 속성의 값으로 주인이 무엇인지 지정한다

누구를 주인으로 삼아야 하는가?

  • 양방향은 외래 키가 있는 곳을 주인으로 정한다
  • 여기서는 Member의 team이 연관관계의 주인이다
  • DB입장에는, 외래키가 있는 곳이 다(N). 외래키가 없는 곳이 무조건 1이다
  • 즉, Team의 members에 값을 넣고 변경해봤자 아무 일도 일어나지 않는다. 주인이 아닌 쪽은 읽기만 할 수 있다
  • 비즈니스적으로 중요한 것이 주인이 되는 것이 아니라, DB 테이블로 따져서 N쪽인 곳이 주인이 되면 된다
    예를 들어, 자동차와 자동차 바퀴에서는 자동차 바퀴가 N이며 연관관계의 주인이다

(1) 다대일 단방향 [N:1]

  • 데이터베이스 테이블의 일(1), 다(N) 관계에서 외래 키는 항상 다쪽에 있다.
  • 팀에는 회원을 참조하는 필드가 없다. 따라서 다대일 단방향 연관관계

(2) 다대일 양방향 [N:1, 1:N]

  • Member의 team이 연관관계의 주인이다. JPA는 외래 키를 관리할 때 연관관계의 주인만 사용한다.
  • 양방향 연관관계는 항상 서로를 참조해야 한다.

(3) 일대다 단방향 [1:N]

  • 하나의 팀은 여러 회원을 참조할 수 있는데 이런 관계를 일대다 관계라 한다. 그리고 팀은 회원들을 참조하지만 회원은 팀을 참조하지 않으면 둘의 관계는 단방향이다.
  • 일대다 관계에서는 반대편 테이블이 외래 키를 관리한다.

(4) 일대다 양방향 [N:1, 1:N]

  • 일대다 양방향 매핑은 존재하지 않는다. 대신 다대일 양방향 매핑을 사용해야 한다.
  • 양방향 매핑에서 @OneToMany는 연관관계의 주인이 될 수 없다. 관계형 데이터베이스의 특정 상 일대다, 다대일 관계는 항상 다 쪽에 외래 키가 있다. 따라서 @OneToMany, @ManyToOne 둘 중에 연관관계의 주인은 항상 다 쪽인 @ManyToOne을 사용한 곳이다

(5) 일대일 단방향 [1:1]

  • ex) 회원과 사물함의 관계
  • 회원과 사물함의 관계는 회원은 하나의 사물함만 사용하고 사물함도 하나의 회원에 의해 사용되므로 일대일 관계

(6) 다대다 단방향 [N:N]

  • 관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.
    그래서 보통 다대다 관계를 일대다, 다대일 관계로 풀어내는 연결 테이블을 사용한다.
  • 그런데 객체 2개로는 다대다 관계를 만들 수 있다. 회원 객체는 컬렉션을 사용해 상품을 참조하고, 반대로 상품들도
    컬렉션을 사용해 회원을 참조하면 된다.
  • @ManyToMany를 이용하면 다대다 관계를 편리하게 매핑 가능하지만 실무에 적합 X

(7) 다대다 양방향 [N:N]

  • 회원과 상품. 회원은 여러 개의 상품을 구매할 수 있고 상품은 여러 회원에 의해 구매됨.

@ManyToMany의 한계

  • 연결 테이블에 단순히 주문한 회원 아이디와 상품 아이디만 담고 끝나지 않는다. 보통은 주문 수량 컬럼이나 주문한
    날짜 같은 컬럼이 더 필요하다.
  • 컬럼을 추가해도 회원이나 상품 엔티티에 추가한 컬럼을 매핑할 수 없다

다대다 -> 일대다 + 다대일

  • 결국, 연결 테이블을 매핑하는 연결 엔티티를 만들고 이곳에 추가한 컬럼들을 매핑해야 한다.
  • 엔티티 간의 관계도 테이블 관계처럼 다대다 -> 일대다 + 다대일 관계로 풀어야 한다.

다대다 -> 일대다 + 다대일 (새로운 기본 키 사용)

  • 복합 키를 만들지 않고 새로운 기본 키를 데이터베이스에서 자동으로 생성해주는 대리 키로 생성하는 방법
  • 이 때 받아온 식별자는 외래 키로만 사용하고 새로운 식별자를 추가하는 관계를 비식별 관계라고 한다.
profile
@chhaewxn

0개의 댓글