ORM - entity, association

0ne·2024년 7월 4일

JPA

목록 보기
2/3

Object-RDB Mapping

entity mapping

DDL(DataDefinitionLanguage)을 application 실행 시점에 자동 생성 → database schema(Tables, Field/columns, relationships ...)가 자동 생성됨

  • 이때 database dialect를 사용하여 적절한 DDL생성
  • 테이블 중심에서 객체 중심으로
  • 개발 서버에서만 사용해야 함! (운영 서버에서는 사용 ㄴㄴ or 다듬어서 사용)

개요

CategoryAnnotations
객체와 테이블 매핑@Entity, @Table
필드와 컬럼 매핑@Column
기본 키 매핑@Id
연관관계 매핑@ManyToOne, @JoinColumn

hibernate.hbm2ddl.auto

  • 운영 장비에는 절대 create, create-drop, update 사용하면 안됨
  • local서버에서만 update, create사용하자

Object - table mapping

@Entity

@Entity가 붙은 클래스를 entity라 하고, JPA가 관리한다.
실제 DB 테이블과 매핑되는 핵심 클래스로, 데이터베이스의 테이블에 존재하는 컬럼들을 필드로 가지는 객체

속성 name

JPA에서 사용할 entity의 이름.
기본값 = 클래스 명


field와 Column mapping

@Column 매핑 사용

속성은 다음과 같다

enum타입의 경우 @Enumerated(EnumType.STRING)

매핑하지 않으려면 @Transient

긴 것은 @Lob이용


PrimaryKey mapping

  • 기본 키 제약 조건: null 아님, 유일, 변하면 안된다.

  • but, 미래까지 이 조건을 만족하는 자연키는 찾기 어렵다. 대리키(대체키)를 사용하자.
    예를 들어 주민등록번호도 기본 키로 적절하기 않다.

    ⟹ 권장: Long형 + 대체키 + 키 생성전략(AUTO_INCREMENT, SEQUENCE_OBJECT 사용 등)

    • 직접 할당: @Id만 사용
    • 자동 생성 : @GeneratedValue 사용
      Generation StrategyDescriptionDatabaseAdditional Annotation
      IDENTITY데이터베이스에 위임MYSQLNone
      SEQUENCE데이터베이스 시퀀스 오브젝트 사용ORACLE@SequenceGenerator
      TABLE키 생성용 테이블 사용, 모든 DB에서 사용All Databases@TableGenerator
      AUTO방언에 따라 자동 지정, 기본값DefaultNone

1) IDENTITY 전략 : 기본 키 생성을 데이터베이스에 위임

  • MySQL, PostgresQL,,
  • JPA는 보통 트랜잭션 커밋 시점에 INSERT SQL 실행한다 그러나 AUTO_ INCREMENT는 데이터베이스에 INSERT SQL을 실행한 이후에 PK값이 나오기 때문에
  • 따라서 IDENTITY 전략은 em.persist() 시점에 즉시 INSERT SQL 실행 하고 DB에서 식별자를 조회
	@Entity
    public class Member {
    	@Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;

2) SEQUENCE 전략

database sequence = 유일한 값을 순서대로 생성하는 DB Object

  • oracle, PostgresQL, H2
	@Entity
    @SequenceGenerator(
    	name = "MEMBER_SEQ_GENERATOR",
        sequenceName = "MEMBER_SEQ",
        initialValue = 1, allocationSize = 50)
    public class Member {
    	@Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        private Long id;

TABLE 전략

키 생성 전용 테이블을 하나 만들어서 database sequence를 흉내내는 전략

  • 모든 DB에 적용가능
  • 성능이 안좋음

association mapping

  • 객체의 reference와 table의 foreign Key를 mapping
  • table은 FK로 join해서 연관 Table을 찾음
  • 객체는 참조를 사용해서 연관된 객체를 찾음

1. 단방향 mapping만으로 일단 설계를 완료해야 함

테이블 설계를 같이 그리면서 객체 설계가 일어나야 함
이때 단방향으로 설계를 끝내야 함

단방향으로 이미 설계가 완료된 것

단지 역방향으로 조회하기 위해 단방향을 필요할 때만 또 추가해서 양방향을 만드는 것이다.

  • JPQL에서 역방향으로 탐색해야할 일이 많음
  • 어플리케이션 개발 때 추가

양방향 association

  • table의 경우, FK가 다른 테이블에서 PK이므로 FK하나로 양쪽을 다 알 수 있다(양쪽으로 join가능)
  • 객체의 양방향 관계는 사실상 서로 다른 2개의 단방향 관계이다.
따라서 객체의 두 관계 중 하나를 연관관계의 주인으로 지정해 이것 만이 외래키를 관리(등록, 수정)할 수 있어야 한다.
FK가 있는 쪽을 주인으로 정하자. 비즈니스적으로 중요한 쪽이 주인이 되는 것이 아니다.
  • 1 : N이면 N이 주인
  • 주인이 아닌쪽은 읽기만 가능
  • 주인은 mappedBy속성을 사용하면 ㄴㄴ, 주인이 아닌 쪽이 mappedBy로 주인을 지정해야 함

주의점

1. 연관관계 Owner에 값을 입력해야 한다. 또한 순수한 객체 관계를 고려해 항상 양쪽에 값을 입력해야 한다.
2. 양쪽에 값을 입력할 수 있도록 association helper method를 작성하자.
3. 무한 loop
lombok에서 toString()만드는 것은 웬만하면 쓰지 마라
JSON생성 라이브러리 : controller에는 Entity를 반환하면 안된다.

3. 연관관계 mapping시 고려사항

1) 다중성 2) 단방향, 양방향 3) 연관관계의 주인

@JoinColumn(name = "매핑할 외래키 이름")

다대일 (가장 많이 쓰는.)


일대다

  • 다대일의 반대
  • entity가 관리하는 FK가 다른 테이블에 존재
  • 연관관계 관리를 위해 추가로 UPDATE sql 실행

    ⟹ 다대일 양방향으로 사용하자. (객체에서 참조를 하나 더 넣는 한이 있더라도)

일대일

  • DB입장에선 외래 키의 DB 유니크 제약조건이 추가된 것
  • 한마디로 정리하면, 객체는 상응하는 table만 관리할 수 있다


    (주 테이블에 FK가 있는 경우만 제시한 것임)
    (대상 테이블에 FK가 있는 경우도 가능)

다대다 : 쓰면 안됨

  • RDB는 정규화된 Table2개로 다대다 관계를 표현할 수 없음
  • 연결테이블을 추가해서 일대다 + 다대일 관계로 풀어내야 함

4. 상속관계 association mapping

  • RDB는 상속관계가 없음
  • 조인전략을 기본으로 하되, 너무 단순하고 확장성이 없는 경우 단일테이블 전략으로 전환하자.

전략1. @Inheritance(strategy = InheritanceType.JOINED)

장점 : 1) Data가 정규화, 설계가 깔끔 2) 제약조건을 아이템에 걸어서 맞출 수 있음 3) 저장공간 효율화
단점 : 1) 조회시 join을 많이 사용, 성능 저하 2) 조회 쿼리가 복잡 3) 데이터 저장시 Insert sql 2번 호출

전략2. @Inheritance(strategy = InheritanceType.SINGLE_TABLE)

dtype을 자동으로 추가해 줌
장점 1) join이 필요가 없으므로 조회가 빠름 2) 조회 쿼리가 단순
단점 1) ((치명적)) 자식 엔티티가 매핑한 칼럼은 모두 null허용 2) 단일 테이블에 모든 것을 저장하므로 테이블이 커질 수 있어 상황에 따라 성능저하 가능

전략3. (아무도 추천하지 않는 전략) @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

@MappedSuperclass

상속관계 매핑이 전혀 아니라, 단순히 entity가 공유하는 속성을 같이 쓰고 싶을 때
주로 등록일, 수정일, 등록자, 수정자 같은 전체 엔티티에서 공통 으로 적용하는 정보를 모을 때 사용

주로 registerDate, lastModifiedDate, registorName, modifierName과 같은 전체 entity에서 공통으로 적용하는 정보를 모을 때 사용
부모 클래스를 상속 받는 자식 클래스에 매핑 정보만 제공 조회
검색 불가(em.find(BaseEntity) 불가)
직접 생성해서 사용할 일이 없으므로 추상 클래스 권장
참고로, 엔티티 객체에서 extend할 수 있는 것은 @MappedSuperclass이거나 @Entity인 엔티티만 가능하다.

profile
@Hanyang univ(seoul). CSE

0개의 댓글