Updated:

1. 개요

JPA는 객체와 테이블, 필드와 컬럼, 기본키 등 엔티티를 적절하게 매핑시켜주는 것이 중요하다. 이번에는 엔티티 매핑에 대해 알아보도록 하자.

2. 객체와 테이블 매핑

2-1. @Entity

JPA가 관리하는 테이블을 엔티티라고 한다. @Entity annotation을 이용하여 테이블과 매핑할 수 있는데, ① 기본 생성자 필수, ② final 클래스, inner 클래스, enum, interface 사용 불가, ③ 값을 저장할 필드에 final 사용 불가 이 세 가지 조건을 만족해야 한다.

1) name 속성

  • 엔티티의 이름을 지정하는 속성으로, 지정하지 않으면 클래스의 이름을 그대로 사용한다.

[소스 코드]

1
2
3
4
5
6
7
8
@Entity(name = "Members")
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
}

[실행 결과]

2-2. @Table

엔티티와 매핑할 테이블을 지정하는 annotation이다.

1) name 속성

  • 매핑할 테이블의 이름을 지정하는 속성으로, 지정하지 않으면 엔티티의 이름을 그대로 사용한다.

2) catalog 속성

  • catalog 기능이 있는 데이터베이스에서 catelog를 매핑한다.

3) schema 속성

  • schema 기능이 있는 데이터베이스에서 schema를 매핑한다.

4) uniqueConstraint 속성

  • DDL 생성 시 유니크 제약조건 생성. 스키마 자동생성을 통해 테이블을 생성할 때에만 사용되고, 실제 로직에는 영향을 주지 않는다.

[소스 코드]

1
2
3
4
5
6
7
8
9
10
11
@Entity
@Table(uniqueConstraints = {
        @UniqueConstraint(name = "uk_name", columnNames = "name")
})
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
}

[실행 결과]

3. 필드와 컬럼 매핑

3-1. @Column

필드와 컬럼을 매핑하기 위한 annotation이다.

1) name 속성

필드와 매핑할 테이블 컬럼의 이름을 설정하기 위한 속성으로, 기본값으로 필드 이름을 갖는다.

[소스 코드]

1
2
3
4
5
6
7
8
9
@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "name")
    private String username;
}

[실행 결과]

2) insertable, updatable 속성

등록 가능여부, 변경 가능여부를 설정하기 위한 속성으로, 기본값은 TRUE이다.

3) nullable 속성

null 값 허용 여부를 설정하기 위한 속성으로, false로 설정하면 DDL 생성 시 not null 제약조건이 붙는다. 기본값은 true이다.

[소스 코드]

1
2
3
4
5
6
7
8
9
@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

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

[실행 결과]

4) unique 속성

한 컬럼에 유니크 제약조건을 걸기 위한 속성이다.

5) columnDefinition 속성

컬럼 정보를 직접 넣어주기 위한 속성이다. (ex. varchar(10) default ‘NONAME’)

[소스 코드]

1
2
3
4
5
6
7
8
9
@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "name", columnDefinition = "varchar(10) default 'NONAME'")
    private String username;
}

[실행 결과]

6) length 속성

컬럼의 길이를 제한하기 위한 속성으로, String에서만 사용하고, 기본값은 255이다.

[소스 코드]

1
2
3
4
5
6
7
8
9
@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "name", length = 10)
    private String username;
}

[실행 결과]

7) precision, scale 속성

BigDecimal타입에서 사용하는데, precision은 소수점을 포함한 전체 자리수, scale은 소수의 자리수를 설정하기 위한 속성이다. 기본값은 precision은 19, scale은 2이다.

3-2. @Temporal

날짜 타입을 매핑하기 위한 annotation이다. LocalDate, LocalDateTime을 사용할 경우에는 생략할 수 있다.

1) value 속성

  • TemporalType.DATE : 데이터베이스의 date 타입과 매핑(2022-01-01)

  • TemporalType.TIME : 데이터베이스의 time 타입과 매핑(15:00:00)

  • TemporalType.TIMESTAMP : 데이트베이스의 timestamp 타입과 매핑(2022-01-01 15:00:00)

3-3. @Enumerated

enum 타입을 매핑하기 위한 annotation이다.

1) value 속성

  • EnumType.ORDINAL : enum의 순서를 데이터베이스에 저장

  • EnumType.STRING : enum의 이름을 데이터베이스에 저장

3-4. Lob

BLOB, CLOB 타입과 매핑하기 위한 annotation이다. 속성이 존재하지 않으며, 매핑 필드타입이 문자이면 CLOB, 나머지는 BLOB과 매핑된다.

3.5 Transient

필드를 컬럼과 매핑시키지 않기 위한 annotation이다. 해당 annotation을 사용하면 데이터베이스에 저장 및 조회를 하지 않는다.

4. 기본키 매핑

4-2. @Id

기본키를 매핑하기 위한 annotation이다. 해당 annotation만 사용할 경우 기본키를 직접 할당하게 된다.

4-3. @GeneratedValue

기본키 생성 전략에 따라 기본키를 자동으로 생성하기 위한 annotation이다.

1) strategy 속성

  • GenerationType.AUTO : 데이터베이스 방언에 따라 해당 데이터베이스가 사용하는 기본키 전략 사용

  • GenerationType.IDENTITY : 데이터베이스에 기본키 생성을 위임(MYSQL)

  • GenerationType.SEQUENCE : 데이터베이스 Sequence 오브젝트 사용. @SequenceGenerator 필요 (ORACLE)

  • GenerationType.TABLE : 키 생성을 위한 테이블 따로 사용. @TableGenerator 필요

5. 기본키 생성 전략

5-1. IDENTITY 전략

데이터베이스에 기본키 생성을 위임하는 전략이다. 영속성 컨텍스트에서 관리가 되려면 PK값이 있어야 하는데, IDENTITY 전략은 INSERT 쿼리를 실행해야 PK를 알 수 있기 떄문에, IDENTITY 전략에서는 커밋하는 시점이 아닌 em.persist()를 호출하는 시점에 INSERT 쿼리를 실행한다.

[소스 코드]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Member.java
@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// JpaMain.java
public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try {
            Member member = new Member();
            member.setName("aiden");
            System.out.println("==========");
            em.persist(member);
            System.out.println("==========");
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
}

[실행 결과]

5-2. SEQUENCE 전략

유일한 값을 순서대로 생성하는 전략으로, call next value for MEMBER_SEQ로 다음값을 얻어올 수 있으므로 쿼리를 모아서 실행할 수 있다. @SequenceGenerator를 통해 Sequence를 설정해주어야 한다.

5-2-1. @SequenceGenerator

1) name 속성

해당 기본키 Generator의 이름이다.

2) sequenceName 속성

데이터베이스에 등록되어있는 시퀀스 이름을 지정하는 속성이다.

3) initialvalue 속성

시퀀스에서 처음 시작하는 값을 지정하기 위한 속성으로, 스키마 자동생성시에만 사용되며, 기본값은 1이다.

4) allocationSize 속성

시퀀스를 한 번 호출할 때 증가하는 수를 지정하기 위한 속성으로, 기본값은 50이다. 시퀀스 한 번 호출로 데이터베이스에 50개의 값을 미리 할당하고, 메모리에서 하나씩 증가시키며 50이 되었을 때 다시 50개를 할당하여 호출 횟수를 줄일 수 있다. 여러 웹서버가 있어도 한 대는 1~50, 다른 한 대는 51~100을 할당하게 되므로 동시성 이슈 없이 실행가능하다.

5) catalog, schema 속성

데이터베이스 catalog, schema 이름을 지정하기 위한 속성이다.

[소스 코드]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Member.java
@Entity
@SequenceGenerator(name = "MEMBER_SEQ_GENERATOR",
        sequenceName = "MEMBER_SEQ",
        initialValue = 1,
        allocationSize = 50)
public class Member {

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

    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// JpaMain.java
public class JpaMain {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();

        try {
            Member member = new Member();
            member.setName("aiden");
            System.out.println("==========");
            em.persist(member);
            System.out.println("==========");
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
        } finally {
            em.close();
        }
        emf.close();
    }
}

[실행 결과]

5-3. TABLE 전략

키 생성을 위한 테이블을 따로 만들어서 SEQUENCE 전략과 동일한 방식으로 키를 생성하는 전략으로, 모든 데이터베이스에 적용 가능하지만, 매번 테이블을 조회하므로 성능상의 이슈가 있다.

5-2-1. @TableGenerator

1) name 속성

해당 기본키 Generator의 이름이다.

2) table 속성

키 생성을 위한 테이블의 이름을 지정하는 속성이다.

3) pkColumnName 속성

시퀀스가 저장될 컬럼 이름을 지정하는 속성으로, 기본값은 sequence_name이다.

4) valueColumnNa 속성

시퀀스의 값이 저장될 컬럼 이름을 지정하는 속성으로, 기본값은 next_val이다.

5) pkColumnValue 속성

키로 사용할 값 이름으로, 기본값은 엔티티의 이름이다.

6) initialValue 속성

초기 값을 지정하는 속성으로, 기본값은 0이다.

7) allocationSize 속성

시퀀스를 한 번 호출할 때 증가하는 수를 지정하기 위한 속성으로, 기본값은 50이다.

8) catelog, schema 속성

데이터베이스 catalog, schema 이름을 지정하기 위한 속성이다.

9) uniqueConstraint 속성

유니크 제약조건을 지정하기 위한 속성이다.

출처 : 자바 ORM 표준 JPA 프로그래밍 - 기본편

Updated:

Leave a comment