엔티티 매핑

0taetae·2025년 1월 9일
post-thumbnail
  • 객체와 테이블 매핑 : @Entity, @Table
  • 기본키 매핑 : @Id
  • 필드와 칼럼 매핑 : @Column
  • 연관관계 매핑 : @ManyToONe, @JoinColumn

💡 엔티티 클래스 제약 조건

  • @Entity 적용해야 한다.
  • @Id 적용해야 한다.
  • 인자 없는 기본생성자 필요
  • 기본 생성자는 public 이나 protected여야 한다
  • 최상위 클래스여야 한다
  • final이면 안된다.

📙객체와 테이블 매핑

💡@Entity

테이블과 매핑할 클래스는 @Entity 어노테이션을 필수로 붙여야 한다.

  • 속성
    • name
      • 엔티티 이름을 지정한다.
      • 기본값은 클래스 이름이다.
  • 적용 시 주의사항
    • JPA가 엔티티 객체를 생성할 때 기본 생성자를 사용하므로 기본 생성자는 필수이다.
      • 자바는 생성자가 하나도 없으면 기본 생성자를 자동으로 만든다.
      • 생성자를 하나 이상 만들면 자바는 기본 생성자를 자동으로 만들지 않으므로, 직접 만들어야 한다.
    • final 클래스, enum, interface, inner 클래스에는 사용할 수 없다.
    • 저장할 필드에 final을 사용하면 안 된다.

💡@Table

  • 엔티티와 매핑할 테이블을 지정한다.
  • 속성
    • name : 테이블 이름(생략하면 클래스 이름과 동일한 이름)
    • catalog : 카탈로그 이름 (ex. MySQL DB 이름)
    • schema : 스키마 이름(ex. 오라클 스키마 이름)
    • 유니크 제약조건
      • 스키마 자동 생성 기능을 사용해서 DDL을 만들 때만 사용한다.
      • 2개 이상의 복합 유니크 제약조건도 만들 수 있다.

📙데이터베이스 스키마 자동 생성

JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원한다.

💡설정

스키마 자동 생성 기능을 사용하기 위해서 persistence.xml에 설정이 필요하다.

다음 속성을 추가하면, 애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성한다.

<property name="hibernate.hbm2ddl.auto" value="create" />

다음 속성을 추가하면, 콘솔에 실행되는 데이블 생성 DDL을 출력할 수 있다.

<property name="hibernate.show_sql" value="true" />

✔️ 스키마 자동 생성 기능이 만든 DDL은 운영 환경에서 사용할 만큼 완벽하지 않으므로 개발환경에서 사용하거나 매핑을 어떻게 해야하는지 참고 정도로만 사용하는 것이 좋다.

💡hibernate.hbm2ddl.auto 속성

  1. create
    • 기존 테이블을 삭제하고 새로 생성한다 (DROP + CREATE)
  2. create-drop
    • create 속성에 추가로 애플리케이션을 종료할 때 생성한 DDL을 제거한다. (DROP + CREATE + DROP)
  3. update
    • 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정한다.
  4. validate
    • 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고 애플리케이션을 실행하지 않는다.
    • DDL을 수정하지 않는다.
  5. none
    • 유효하지 않은 옵션 값이다.

✔️ 자동 생성 기능을 사용하지 않으려면 속성 자체를 삭제하거나 유효하지 않은 옵션 값을 주면 된다.

📙DDL 생성 기능

@Column 매핑 정보의 속성 값을 지정하여 제약조건을 추가했을때, 이 제약조건들은 단지 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.

📙기본 키 매핑

기본 키를 애플리케이션에서 직접 할당하는 대신에 DB가 생성해주는 값을 사용하려면 어떻게 매핑해야 할까?

  1. 기본 키 직접 할당 전략

  2. 자동 생성 전략

    • 대리 키 사용 방식
    • IDENTITY 전략, SEQUENCE 전략, TABLE 전략
    • GenerationType.AUTO
    • 다음 속성을 추가해야 한다.
    <property name="hibernate.id.new_generator_mappings" value="true" />
    • DB를 변경해도 코드를 수정할 필요가 없다.
    • SEQUENCE나 TABLE 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 한다.

💡기본 키 직접 할당 전략

기본 키를 애플리케이션에서 직접 할당한다.

  • @Id만 사용하면 된다.
  • @Id로 매핑
    @Id
    @Column(name = "id")
    private String id;
  • @Id 적용 가능 자바 타입
    • 자바 기본형
    • 자바 Wrapper형
    • String
    • java.util.Date
    • java.sql.Date
    • java.math.BigDecimal
    • java.math.BigInteger
  • em.persist()로 엔티티를 저장하기 전에 애플리케이션에서 기본 키를 직접 할당하는 방법이다.
    Board board = new Board();
    board.setId("id1");  // 기본 키 직접 할당 
    em.persist(board);
  • 식별자 값이 없으면 예외가 발생한다.

💡IDENTITY 전략

기본 키 생성을 DB에 위임한다.

  • 테이블을 생성할 때 기본키 칼럼을 추가한다.
    -> DB에 값을 저장할 때 해당 칼럼을 비워두면 DB가 순서대로 값을 채워준다.
  • @GeneratedValue의 strategy 속성 값을 GenerationType.IDENTITY로 지정해야 한다.
    @Id
    @GeneratedVAlue(strategy = GenerationType.IDENTITY)
    private Long id;
  • 데이터를 DB에 INSERT한 후에 기본 키 값을 조회할 수 있다.
    -> 엔티티에 식별자 값을 할당하려면 JPA는 추가로 DB를 조회해야 한다.
  • IDENTITY 식별자 생성 전략은 엔티티를 DB에 저장해야 식별자를 구할 수 있다.
    -> em.persist()를 호출하는 즉시 INSERT SQL이 DB에 전달된다.
    -> 트랜잭션을 지원하는 쓰기 지연이 동작하지 않는다.
  • 엔티티를 DB에 저장한 후에 식별자를 조회해서 엔티티의 식별자에 할당한다.

💡SEQUENCE

DB 시퀀스를 사용해서 기본 키를 할당한다.

✔️ DB 시퀀스란❓
유일한 값을 순서대로 생성하는 특별한 DB Object

  • @SequenceGenerator를 사용해서 시퀀스 생성기를 등록한다.
    -> 시퀀스 생성기를 실제 DB의 시퀀스와 매핑한다.
    -> 키 생성 전략을 GenerationType.SEQUENCE로 설정, generator로 방금 등록한 시퀀스 생성기를 선택한다.
    => 식별자 값은 시퀀스 생성기가 할당한다.
  • em.persist()를 호출할 때 먼저 DB 시퀀스를 사용해서 식별자를 조회한다.
    -> 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장한다.
    -> 트랜잭션을 커밋해서 플러시가 일어나면 엔티티를 DB에 저장한다.
  • @SequenceGenerator
    • name : 식별자 생성기 이름
    • sequenceName : DB에 등록되어 있는 시퀀스 이름
    • initialValue : DDL 생성 시에만 사용됨, 시퀀스 DDL을 생성할 때 처음 시작하는 수를 지정
    • allocationSize : 시퀀스 한 번 호출에 증가하는 수
    • catalog, schema : 데이터베이스 catalog, schema 이름

💡TABLE

키 생성 테이블을 사용한다.

  • 키 생성 전용 테이블을 하나 만들고 이름과 값으로 사용할 칼럼을 만들어 DB 시퀀스를 흉내내는 전략
  • 테이블을 사용하므로 모든 DB에 적용할 수 있다.
  • @TableGenerator를 사용해서 케이블 키 생성기를 등록한다.
    -> 생성한 테이블을 키 생성용 테이블로 매핑
    -> GenerationType.TABLE 선택
    -> @GeneratedValue.generator에 만든 테이블 키 생성기를 지정
    => 식별자 값은 해당 테이블 키 생성기가 할당
  • @TableGenerator
    • name : 식별자 생성기 이름
    • table : 키 생성 테이블명
    • pkColumnName : 시퀀스 칼럼명
    • valueColumnName : 시퀀스 값 칼럼명
    • pkColumnValue : 키로 사용할 값 이름
    • initialValue : 초기 값, 마지막으로 생성된 값이 기준이다.
    • allocationSize : 시퀀스 한 번 호출에 증가하는 수
    • catalog, schema
    • uniqueConstraints(DDL) : 유니크 제약 조건을 지정할 수 있다.

📙필드와 칼럼 매핑

💡@Column

  • 객체 필드를 테이블 칼럼에 매핑
  • 속성
    • name
      • 필드와 매핑할 테이블의 칼럼 이름
      • default : 객체의 필드 이름
    • nullable(DDL)
      • null 값의 허용 여부 설정
      • default : true
      • false로 설정하면 DDL 생성 시에 not null 제약조건이 붙는다.
    • unique(DDL)
      • 한 칼럼에 간단히 유니크 제약조건을 걸 때 사용
    • length(DDL)
      • 문자 길이 제약조건
      • String 타입에만 사용
    • precision, scale(DDL)
      • BigDecimal 타입에서 사용
      • precision : 소수점을 포함한 전체 자릿수
      • scale : 소수의 자릿수
      • double, float 타입에는 적용하지 않는다.
      • 아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용
      • default : precision=19, scale=2

💡@Enumerated

  • 자바의 enum 타입을 매핑할 때 사용
  • value
    • EnumType.ORDINAL
      • enum 순서를 DB에 저장
      • 숫자 타입 칼럼에 매핑
      • default
      • DB에 저장되는 데이터 크기가 작다.
      • 이미 저장된 enum의 순서를 변경할 수 없다.
    • EnumType.STRING
      • enum 이름을 DB에 저장
      • 문자열 타입 칼럼에 매핑
      • 저장된 enum의 순서가 바뀌거나 enum이 추가되어도 안전하다.
      • DB에 저장되는 데이터 크기가 ORDINAL에 비해서 크다.

💡@Temporal

  • 날짜 타입(java.util.Date, java.util.Calender)을 매핑할 때 사용
  • value
    • TemporalType.DATE : 날짜, 데이터베이스 date 타입과 매핑
    • TemporalType.TIME : 시간, 데이터베이스 time 타입과 매핑
    • TemporalType.TIMESTAMP : 날짜와 시간, 데이터베이스 timestamp 타입과 매핑
  • @Temporal을 생략하면 다음과 같이 정의된다.
    • timestamp : H2, 오라클, PostgreSQL

💡@Lob

  • 데이터베이스 BLOB, CLOB 타입과 매핑
  • 속성
    • CLOB : String, char[], java.sql.CLOB
    • BLOB : byte[], java.sql.BLOB

💡Transient

  • 데이터베이스에 저장하지 않고 조회하지도 않는다.
  • 객체에 임시로 어떤 값을 보관하고 싶을 때 사용한다.

💡Access

  • JPA가 엔티티 데이터에 접근하는 방식을 지정
  • 클래스/개별 필드에 적용 가능
  1. 필드 접근

    • AccessType.FIFLD로 지정
    • 필드에 직접 접근
    • 필드 접근 권한이 private이어도 접근할 수 있다.
    • @Id 어노테이션을 필드에 붙인다.
  2. 프로퍼티 접근

    • AccessType.PROPERTY로 지정
    • 접근자(Getter)를 사용
    • @Id 어노테이션을 getter 메서드에 붙인다.

📙매핑 어노테이션 사용해보기

@Entity  // 매핑 대상 엔티티
@Table(name = "hotel_info")  // hotel_info 테이블에 매핑
public class Hotel {
   @Id  // 식별자로 매핑
   @Column(name = "hotel_id")  // hotel_id 칼럼에 매핑
   private String id;
   
   @Column(name = "nm")
   private String name;
   
   private int year;  // year 칼럼에 매핑
   
   @Enumerated(EnumType.STRING)  // 열거 타입 이름을 값으로 저장
   private Grade grade;
   
   private LocalDateTIme created;
   
   @Column(name = "modified")
   private LocalDateTime lastModified;

0개의 댓글