1. Hibernate의 DB 테이블 자동 생성


들어가기에 앞서, 개발 및 로컬 환경에서 테스트를 용이하게 하는 DB 테이블을 자동으로 생성해주는 기능을 알아보겠습니다.
보통 개발할때 DB 테이블을 먼저 만드는데요, Hibernate에서 지원하는 DB 테이블 생성 기능을 사용하면 이 과정을 생략할 수 있습니다.
/META-INF/persistence.xml 설정 파일에 다음과 같이 hibernate.hbm2ddl.auto 옵션을 설정해줍니다.

<persistence-unit name="hello">
  <properties>
    <property name="hibernate.hbm2ddl.auto value="create" />
  </properties>
</persistence-unit>

해당 옵션의 값으로는 create, create-drop, update, none 이 있는데요, Entity 클래스를 보고 자동으로 테이블 생성 쿼리를 날립니다.

2. Entity 클래스와 DB 테이블 매핑하기


해당 Entity 클래스가 DB의 어떤 테이블과 매핑되는지를 설정하는 방법입니다.

@Entity(name = "MBR") // 해당 Entity 클래스와 매핑될 테이블명을 지정합니다.
@Table(name = "MBR") // 해당 Entity 클래스와 매핑될 테이블명을 지정합니다.
public class Member {
  ...
}

@Entity 애너테이션에 name 속성도 매핑될 테이블명을 설정하는 것이고, @Table의 name 속성도 매핑될 테이블명을 설정합니다.
아직 둘의 차이점은 찾지 못했습니다.

3. Entity 클래스의 필드와 DB 테이블의 컬럼 매핑하기


Entity 클래스의 필드에 각종 애너테이션을 붙임으로써 DB 테이블 컬럼은 어떤 타입으로 할지, 어떤 옵션을 가질지를 설정할 수 있습니다.

@Entity 
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    @Column(name = "name")
    private String username;
    
    private int age;
    
    @Enumerated({EnumType.STRING 또는 EnumType.ORDINAL})
    private RoleType roleType;
    
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;
    
    @Lob
    private String description;
}

Enum RoleType {
    USER, ADMIN
}

필드 위에 붙은 애너테이션을 차례대로 하나씩 살펴보겠습니다.
우선 @Id 를 붙이면 해당 필드는 DB 테이블의 primary key가 된다는 의미입니다. 그런데 잘 생각해보시면, DB 테이블의 primary key 컬럼의 값을 직접적으로 개발자가 할당해주는 경우는 거의 없습니다. MySQL이라면 auto_increment를 사용하고, Oracle이라면 sequence를 사용합니다. @Id 밑에 @GeneratedValue(strategy = {기본키값 생성전략}) 이 그런 전략을 의미합니다.
primary key 값 생성 전략으로는 4가지를 설정할 수 있습니다.

  • GenerationType.AUTO
  • GenerationType.IDENTITY
  • GenerationType.SEQUENCE
  • GenerationType.TABLE

 

우선 GenerationType.AUTO부터 살펴보겠습니다.
해당 전략은 GenerationType.SEQUENCE 와 같습니다. (AUTO로 하면 디폴트로 SEQUENCE로 잡히는 것 같습니다.)
GenerationType.AUTO로 하고 실행을 해보면 JPA는 다음과 같은 키 생성용 테이블을 생성합니다.

[그림 1] hibernate_sequence 라는 키 생성용 테이블을 생성한다.

위와 같은 키 생성용 테이블을 generator 라고 부르는데요, 보시면 hibernate_sequence 테이블을 생성하는 것을 볼 수 있습니다. 
우측 그림은 JPA에서 INSERT를 할때 일어나는 동작으로 generator를 조회해서 id 값을 애플리케이션 내에서 세팅합니다. 그리고 UPDATE문을 통해 다음 키 값이 될 값으로 업데이트해주고 있습니다.

 

generator는 크게 세 가지를 개발자가 설정해줄 수 있습니다.

  1. generator 테이블의 이름 (디폴트는 위와 같이 hibernate_sequence입니다.)
  2. initialValue: 위 좌측 그림을 보시면 최초 1을 세팅하는데, 이것을 별도로 설정해줄 수 있습니다.
  3. allocationSize: 디폴트는 generator 값이 1씩 증가하는데, 이것도 설정이 가능합니다.

다음과 같이 generator를 만들고, 적용할 수 있습니다.

@Entity
@SequenceGenerator(
    name = "MEMBER_SEQ_GENERATOR",        // 해당 generator 이름입니다.
    sequenceName = "MEMBER_SEQ",          // generator가될 DB 테이블명입니다.
    initialValue = 1, allocationSize = 50 // 초기값과 할당 사이즈입니다.
)
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "MEMBER_SEQ_GENERATOR")
    private Long id;
}

다음으로 GenerationType.IDENTITY를 살펴보겠습니다.
해당 전략은 필드를 MySQL에서 auto_increment로 설정합니다. 키 값 생성을 DB에서 담당합니다.

@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
}

해당 전략을 채택할 경우 id 값은 DB에 INSERT를 해야 알 수 있습니다. 따라서, 객체를 생성하고 .persist() 시 flush가 자동호출됩니다.

 

다음으로 @Enumerated 애너테이션은 Java의 Enum 타입을 DB 컬럼에서 어떤 타입으로 할건지를 설정하는 것입니다.
두 가지 값이 올 수 있습니다.

  • EnumType.STRING: Enum과 매핑되는 DB 컬럼의 타입이 varchar(255) 입니다. (문자열)
  • EnumType.ORDINAL: Enum과 매핑되는 DB 컬럼의 타입이 Integer입니다. (숫자형)

EnumType.ORDINAL을 사용할 경우 Enum 클래스 내 값들의 순서가 변경되면 이전에 저장한 값들의 의미가 같이 변경되기 때문에 지양해야 합니다. 즉, Enum 타입을 매핑할 일이 있으면 무조건 EnumType.STRING 를 사용하면 됩니다.

 

다음으로 @Temporal 애너테이션은 Java의 날짜/시간 타입을 DB 컬럼에서 어떤 타입으로 할건지를 설정하는 것입니다.
Java 8의 LocalDate, LocalDateTime 타입을 사용할 경우 안 써도 되는 애너테이션이기 때문에 이제는 사용할 일이 없습니다.
@Temporal(TemporalType.TIMESTAMP) 으로 지정하면 DB의 컬럼은 datetime(6) 으로 됩니다.