2020.03.06 수정


Mybatis 버전의 방명록 애플리케이션( 링크 )을 JPA 버전으로 만드는 주제입니다.



JPA를 사용하기 위해서는 DB의 테이블과 Java에서 사용할 객체를 매핑( mapping ) 해야 합니다. ( ORM )

<!-- @Entity 탐색 범위 -->
<property name="packagesToScan" value="com.victolee.guestbook.domain" />

이전 글에서 환경 설정을 할 때, applicationContext.xml 파일에서 스프링이 @Entity 어노테이션을 스캔 할 수 있도록 스캔 범위를 지정해줬습니다.

따라서 클래스에 @Entity을 추가하면 해당 객체와 DB 테이블이 매핑되는데, 이를 엔티티 클래스가 합니다.

이 글에서는 엔티티를 매핑하는 방법에 대해 알아보겠습니다.






1. 엔티티 클래스 정의

com.victolee.guestbook.domain.Guestbook.java

@Entity
@Table(name="guestbook")
public class Guestbook {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer no;

@Column(name="name", nullable=false, length=100)
private String name;

@Column(name="pwd", nullable=false, length=64)
private String pwd;

@Column(name="message", nullable=false)
private String message;

@Temporal(TemporalType.TIMESTAMP)
@Column(name="reg_date", nullable=false)
private Date regDate;

// getter setter 생략
}

어노테이션의 import는 javax.persistenece 패키지입니다.


보시는 바와 같이 Guestbook 클래스에 여러 가지 어노테이션을 추가하면 DB의 guestbook 테이블과 매핑이 이루어집니다.

이렇게 정의한 Guestbook 객체를 엔티티( Entity ) 합니다.


JDBC( Mybatis )에서 사용했던 VO와 비슷하게 생겼는데, 이제부터는 단순 데이터 전달 목적의 객체가 아닌 테이블로서 매핑이 되는 객체라고 생각해야 합니다.

VO의 역할을 대신하여 데이터를 전달하는 객체인 DTO가 있으며, DTO와 Entity는 구분해서 사용하는 것이 좋습니다.



이제 구체적으로 엔티티 매핑에 필요한 몇 가지 어노테이션에 대해 알아보겠습니다




2. @Entity , @Table

@Entity
@Table(name="guestbook")
public class Guestbook {

}

  • @Entity
    • 객체를 테이블과 매핑 할 엔티티라고 JPA에게 알려주는 역할을 합니다. ( 엔티티 매핑 )
    • @Entity가 붙은 클래스는 JPA가 관리하며, 이를 엔티티 클래스라 합니다.
    • @Entity 선언시 주의 사항
      • 기본 생성자는 꼭 존재해야 합니다.
      • final class, inner class, enum, interface에는 사용할 수 없습니다.
      • 필드에 final 을 사용하면 안됩니다.
    • 속성
      • name
        • JPA가 사용할 엔티티 이름을 지정합니다. ( 예제에서는 생략 )
        • name 속성은 기본 값으로 클래스 이름을 사용하기 때문에 name 속성은 생략해도 무방하지만, 만약 다른 패키지에 이름이 같은 엔티티 클래스가 있다면 이름을 지정해서 충돌하지 않도록 해야 합니다.
  • @Table(name="guestbook")
    • 엔티티 클래스에 매핑할 테이블명을 선언합니다.
    • 예제에서는 name 속성을 사용해서 Guestbook 엔티티를 guestbook 테이블에 매핑했습니다.
      • 해당 어노테이션을 생략하면 엔티티 이름을 테이블 이름으로 자동 매핑합니다. ( 대소문자 구분 안함 )
    • 속성
      • name
        • 매핑할 테이블 이름 ( 기본값은 엔티티의 이름)
      • schema
        • schema 기능이 있는 데이터베이스에서 schema를 매핑




2. @Id , @GeneratedValue

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer no;

  • @Id 어노테이션을 작성하면 엔티티의 필드를 테이블의 기본 키( PK, Primary key )에 매핑 합니다.
    • @Id 어노테이션이 있는 필드를 식별자 필드라 합니다.
  • 기본 키 생성 전략 
    • 자동 생성
      • 대리 키 사용 방식, 즉 @GeneratedValue 어노테이션의 strategy( 전략 ) 속성에 따라 기본 키 값이 생성됩니다.
      • AUTO
        • DB 종류에 따라 JPA가 알맞은 것을 선택합니다.
        • ( Oracle은 SEQUENCE , MySQL은 IDENTITY를 선택 )
      • IDENTITY
        • 기본 키 생성을 데이터베이스에 위임합니다.
        • ( MySQL, PostgreSQL, SQL Server, DB2에서 사용 가능 )
      • SEQUENCE 
        • 데이터베이스 시퀀스를 사용해서 기본 키를 할당합니다.
        • ( Oracle, PostgreSQL, DB2, H2 )
      • TABLE 
        • 키 생성 전용 테이블을 만들어서 sequence처럼 사용합니다.
    • 직접 할당
      • PK 값을 JPA에 위임하지 않고, 직접 부여하는 방법입니다.



3. @Column
@Column(name="name", nullable=false, length=100)
private String name;
  • 엔티티의 필드를 테이블의 칼럼에 매핑합니다.
  • 속성
    • name 
      • 필드와 매핑할 테이블의 컬럼 이름 ( 기본값은 필드 이름 )
    • nullable
      • null 값 허용 여부를 설정합니다.
      • 기본 값은 true이며, false일 경우 테이블 정의 시 필드에 NOT NULL 제약 조건이 붙습니다.
    • length
      • 문자 길이 제약 조건으로 기본 값은 255이며, String 타입에만 적용 가능합니다.




4. @Temporal

@Temporal(TemporalType.TIMESTAMP)
@Column(name="reg_date", nullable=false)
private Date regDate;

  • @Temporal 어노테이션은 날짜 타입( java.util.Date , java.util.Calendar )을 매핑 할 때 사용합니다.
  • 속성
    • TemporalType.DATE
      • 날짜, 데이터베이스 date 타입과 매핑
      • ex)  2013–10–11
    • TemporalType.TIME
      • 시간, 데이터베이스 time 타입과 매핑
      • ex)  11:11:11
    • TemporalType.TIMESTAMP
      • 날짜와 시간, 데이터베이스 timestamp(datetime) 타입과 매핑
      • ex)  2013–10–11 11:11:11
  • @Column으로 필드명을 재정의한 이유는 Java에서는 Camel 표기법( regDate )을 사용하고, DB에서는 snake 표기법( reg_date )을 사용하기 때문에 관례를 따랐습니다.



이상으로 Guestbook 엔티티에서 사용한 어노테이션을 알아보았습니다.
Guestbook과 관련은 없지만 추가적으로 어노테이션을 더 알아보겠습니다.



5. @Transient

@Transient
private Integer foo;
  • @Transient 어노테이션이 있는 필드는 매핑이 이루어지지 않습니다.
    • 즉, 데이터베이스에 저장하지 않고 조회하지도 않습니다.
    • 객체에 임시로 어떤 값을 보관하고 싶을 때 사용할 수 있습니다.
    • 예를 들어, 상품이라는 엔티티에 대해서 가격(price)과 할인된 가격(discountPrice) 필드가 있을 때, 할인된 가격은 일시적인 저장용도일 뿐이고, 칼럼으로 사용하고 싶지 않을 수도 있습니다. 




6. @Enumerated
@Enumerated(EnumType.STRING)
@Column( name="kind", nullable=false, columnDefinition = "enum('A','B','C')")
private Enum kind;
  • 자바의 enum 타입을 매핑 할 때 사용합니다.
  • 속성
    • EnumType.ORDINAL
      • 기본값이며, enum의 순서를 데이터베이스에 저장
    • EnumType.STRING
      • enum의 이름을 데이터베이스에 저장

public enum Kind {
A, B, C
}

예를 들어, 위와 같이 Enum 클래스를 생성한 후 @Column의 속성에 columnDefinition을 정의하면,

Book 엔티티의 kind 필드의 값에는 A, B, C 값만 추가할 수 있습니다.

정형화된 데이터를 받을 때 사용하면 좋습니다.





7. 매핑 정보가 없을 때

private String foo;
  • 매핑 어노테이션을 생략하면 필드명을 그대로 컬럼명으로 매핑합니다.
  • 예를 들어, 엔티티의 필드명 foo가 있으면, 매핑된 테이블에도 foo 컬럼으로 자동 매핑됩니다.




이상으로 엔티티 매핑에 대해 알아보았습니다.

<prop key="hibernate.hbm2ddl.auto">create</prop>
참고로 JPA 설정에서 위와 같이 auto create이면, 엔티티 클래스의 어노테이션에 따라 DB 테이블이 자동으로 생성됩니다.


다음 글에서는 본격적으로 JPA를 사용하는 CURD 작업을 하겠습니다.