4 분 소요

자바 ORM 표준 JPA 프로그래밍에서 읽은 내용을 정리하는 글입니다😄

JPA에서 가장 중요한 일은 엔티티와 테이블을 정확히 매핑하는 것이다.
매핑하는데 필요한 어노테이션은 다음과 같다.

  • 객체 ~ 테이블 : @Entity, @Table
  • 기본키 : @Id
  • 필드 ~ 컬럼 : @Column
  • 연관관계 : @ManyToOne, @JoinColumn

4.1 @Entity

테이블과 매핑할 클래스에 반드시 @Entity 어노테이션을 붙여야 한다.
@Entity가 붙은 클래스를 엔티티라 부르며, JPA가 관리하게 된다.
속성으로는 name이 있고 이는 JPA에서 사용할 엔티티 이름을 의미한다.
기본값은 클래스 이름이 된다.

@Entity 사용 시 주의사항은 다음과 같다.

  • 기본 생성자 반드시 사용
  • final, enum, interface, inner 클래스에서 사용 불가
  • 저장할 필드에 final 사용 불가

4.2 @Table

엔티티와 매핑할 테이블에는 @Table 어노테이션을 붙여야 한다.
속성들은 다음과 같다.

  • name : 매핑할 테이블 이름
  • catalog : catalog 기능이 있는 DB에서 catalog 매핑
  • schema : schema 기능이 있는 DB에서 schema 매핑
  • uniqueConstraints(DDL) : DDL 생성 시 유니크 제약조건 생성

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

JPA는 데이터베이스 스키마를 자동 생성하는 기능을 지원한다.
사용 시 애플리케이션 실행 시점에 데이터베이스 테이블이 자동으로 생성되므로
개발자가 직접 생성하는 수고를 덜게 된다.

persistence.xml에 다음 속성을 추가하면 된다.

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

hibernate.hbm2ddl.auto의 속성들은 다음과 같다.

  • create : 기존 테이블을 삭제 후 새로 생성
  • create-drop : create 속성 + 애플리케이션 종료 시 생성한 DDL 제거
  • uplast_modified_at : DB 테이블과 엔티티 매핑정보를 비교해 변경 사항만 수정
  • valilast_modified_at : DB 테이블과 엔티티 매핑정보를 비교해 변경 사항 있으면 경고 남김 (DDL 수정X)
  • none : 자동 생성 기능 사용X

4.4 DDL 생성 기능

회원 이름은 필수로 입력돼야 하며 10자를 초과하면 안된다는 제약조건을 추가하는 상황을
생각해보자. 다음 코드를 추가해주면 된다.

...
@Column(name = "NAME", nullable = false, length = 10) //추가 코드
private String username;
...

이렇게 수정하면 DDL에 not null과 문자 크기 10 제약조건을 추가할 수 있다.
이번엔 유니크 제약조건을 만들어주는 @Table의 uniqueConstraints 속성을 알아보자.

//유니크 제약조건
@Entity(name="Member")
@Table(name="MEMBER", uniqueConstraints = {@UniqueConstraint( //추가 코드
  name = "NAME_AGE_UNIQUE",
  columnNames = {"NAME", "AGE"} )})
public class Member {
  ...
}
//생성된 DDL
ALTER TABLE MEMBER
  ADD CONSTRAINT NAME_AGE_UNIQUE UNIQUE (NAME, AGE)

위에서 설명한 기능들은 DDL 생성 시에만 사용되고 JPA 실행 로직에는 영향을 주지 않는다. 그러나 애플리케이션 개발자가 엔티티만 보고도 제약조건을 쉽게 파악할 수 있다는 장점이 있다.

4.5 기본 키 매핑

기본 키 직접 할당 전략

기본 키를 직접 할당하려면 @Id로 매핑하면 된다.

@Id
@Column(name = "id")
private String id;

em.persist()로 엔티티 저장 전에 애플리케이션에서 기본 키를 직접 할당하는 방법이다.

Board board = new Board();
board.setId("id1"); //기본 키 직접 할당
em.persist(board);
IDENTITY 전략

기본 키 생성을 DB에 위임하는 전략으로, 주로 MySQL, PostgreSQL, SQL Server, DB2
에서 사용한다. @GenerateValue의 stratgy 속성 값을 GenerateType.IDENTITY로 지정하자.
이 전략 사용 시 JPA는 기본 키 값을 얻기 위해 DB를 추가로 조회한다.

//IDENTITY 매핑 코드
@Entity
public class Board {
  
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY) //추가 코드
  private Long id;
  ...
}
//IDENTITY 사용 코드
Board board = new Board();
em.persist(board);
SEQUENCE 전략

DB 시퀀스는 유일한 값을 순서대로 생성하는 특별한 DB 오브젝트로, 이를 통해 기본 키
를 생성한다. 이 전략은 PostgreSQL, DB2, H2에서 사용할 수 있다.

//시퀀스 DDL
CREATE SEQUENCE BOARD_SEQ START WITH 1 INCREMENT BY 1;
//시퀀스 매핑 코드
@Entity
@SequenceGenerator(
  name = "BOARD_SEQ_GENERATOR",
  sequenceName = "BOARD_SEQ", //매핑 DB 시퀀스 이름
  initialValue = 1,
  allocationSize = 1
)
public class Board {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE,
                  generator = "BOARD_SEQ_GENERATOR")
  private Long id;
  ...
}

시퀀스 사용 코드는 IDENTITY 사용 코드와 같지만 내부 동작이 다르다.
IDENTITY 전략은 엔티티를 DB에 저장 후 식별자를 조회해서 엔티티의 식별자에 할당한다.
SEQUENCE 전략은 em.persist()호출 시 먼저 DB 시퀀스를 통해 식별자를 조회하고,
조회한 식별자를 엔티티에 할당 후 엔티티를 영속성 컨텍스트에 저장한다.
이후 트랜잭션을 커밋해 엔티티를 DB에 저장한다.

다음은 @SequenceGenerator 속성들이다.

  • name : 식별자 생성기 이름
  • sequenceName : DB 시퀀스 이름
  • initialValue : DDL 생성 시 시작하는 숫자 지정 (DDL 생성 시에만 사용)
  • allocationSize : 시퀀스 한 번 호출에 증가하는 수 (성능 최적화용)
  • catalog, schema : DB catalog, schema 이름
TABLE 전략

키 생성 전용 테이블을 만들고 이름과 값으로 사용할 컬럼을 만들어 DB 시퀀스를 흉내내는 전략이다.
이 전략은 앞에서 살펴본 전략과 달리 모든 DB에서 사용 가능하다.
TABLE 전략을 사용하려면 키 생성 용도로 사용할 테이블을 만들어야 한다.

//TABLE 전략  생성 DDL
create table MY_SEQUENCES (
  sequence_name varchar(255) not null, //시퀀스 이름
  next_val bigint,                     //시퀀스 
  primary key ( sequence_name )
)

@TableGenerator를 사용해 테이블 키 생성기를 등록한다.
아래 예제에서는 BOARD_SEQ_GENERATOR라는 이름의 테이블 키 생성기를 등록하고,
위에서 생성한 MY_SEQUENCES 테이블을 키 생성용 테이블로 매핑한다.
TABLE 전략을 사용하기 위해 @GeneratedType.TABLE을 선택하고,
@GeneratedValue.generator에 방금 만든 테이블 키 생성기를 지정한다.
이제부터 id 식별자 값은 BOARD_SEQ_GENERATOR 테이블 키 생성기가 할당한다.

//TABLE 전략 매핑 코드
@Entity
@TableGenerator (
  name = "BOARD_SEQ_GENERATOR",
  table = "MY_SEQUENCES",
  pkColumnValue = "BOARD_SEQ", allocationSize = 1)
)
public class Board {

  @Id
  @GeneratedValue(strategy = GenerationType.TABLE,
    generator = "BOARD_SEQ_GENERATOR)
  private Long id;
  ...
}

TABLE 전략 매핑 사용 코드는 이전에 살펴본 매핑 사용 코드와 같다.
내부 동작방식 또한 SEQUENCE 전략과 같다.

@TableGenerator 속성들은 다음과 같다.

  • name : 식별자 생성기 이름
  • table : 키생성 테이블명
  • pkColumnName : 시퀀스 컬럼명
  • valueColumnName : 시퀀스 값 컬럼명
  • pkColumnValue : 키로 사용할 값 이름
  • initialValue, allocationSize, catalog, schema, uniqueConstraints(DDL)
AUTO 전략

GenerationType.AUTO는 선택한 DB 방언에 따라 IDENTITY, SEQUENCE, TABLE 전략 중 하나를 자동으로 선택한다.
가령, 오라클은 SEQUENCE를, MySQL은 IDENTITY를 사용한다.

//AUTO 전략 매핑 코드
@Entity
public class Board {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  ...
}

@GeneratedValue.strategy의 기본값은 AUTO이므로 @GeneratedValue라 써도 결과가 같다.
AUTO 전략의 장점은 DB 변경 시에도 코드를 수정할 필요가 없다는 점이다.
따라서 키 생성 전략이 확정되지 않은 개발 초기 단계 혹은 프로토타입 개발 시 유용하다.

카테고리:

업데이트:

댓글남기기