엔티티 매핑 (Entity Mapping)

박영준·2023년 1월 16일
0

Spring

목록 보기
3/58

Entity 와 Table 을 정확히 매핑하자.

1. 어노테이션

1) @Entity

@Entity(name = "user2")
public class User {
}

(1) 정의

  • Table 과 매핑할 클래스에 붙인다.
  • @Entity 을 붙임으로써, JPA가 해당 클래스를 관리하게 된다.

(2) 속성

  • name
    - JPA에서 사용할 엔티티 이름 지정
    - name을 쓰지 않을 경우 (default) 클래스이름을 엔티티 이름으로 지정

(3) 주의점

  • 기본 생성자는 필수
  • final 클래스, enum, interface, innter 클래스 에서는 사용 X
  • 필드(변수)에 final 사용 X

2) @Table

@Entity
@Table(name = "user3")		// @Table 의 name 을 user3 로 지정
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
}
@Entity(name="user2")		// @Table 에서 name 생략 시, @Entity 의 name 으로 테이블 이름이 지정됨
@Table
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
}

(1) 정의

Entity 와 매핑할 Table 을 지정

(2) 속성

  • name
    - 매핑할 테이블 이름
    - 생략시 : 엔티티 이름(@Entity(name="~") 사용

  • catalog : catalog 기능이 있는 DB 에서 catalog 매핑

  • schema : schema 기능이 있는 DB 에서 schema 매핑

  • uniqueContraints
    - DDL 생성시 유니크 제약조건 생성
    - 2개 이상의 복합 유니크 제약조건 만들 수 있음
    - 스키마 자동 생성 기능을 사용해 DDL을 만들 때만 사용

3) @Id

(1) 정의

특정 속성을 기본키로 설정

(2) 속성 (기본 키 생성 방식)

  • 직접 할당
    : 기본 키를 애플리케이션에서 직접 할당

    @Entity(name="user2")
    @Table
    @Getter
    @Setter
    public class User {
        @Id		// @GeneratedValue 없이 @Id 어노테이션만 적게될 경우, 기본키값을 직접 부여해줘야 한다.
        @GeneratedValue		// 기본값을 DB 에서 자동 생성
        private Long id;
        private String name;
    }
    // 사용 방식
    Board board = new Board(); 		// 객체를 생성하고
    board.setId("id1") 			// 해당객체에 기본 키의 value값을 세팅 → 기본 키 직접 할당 
    em.persist(board);
  • 자동 생성
    : 대리 키 사용

    • @GeneratedValue(startegy = GenerationType.IDENTITY)

      • 기본 키(PK) 생성을 DB에 위임 (Mysql) → DB에 의존 O
      • 선(Entity)저장 후(식별자)조회
        // 선언방식
        @Entity
        public class Board {
           @Id
           @GeneratedValue(strategy = GenerationType.IDENTITY)
           private Long id;
           ...
        }
        // 사용 방식
        private static void logic(EntityManager em) {
         Board board = new Board();
         em.persist(board);		// Board 객체를 DB에 저장하고 (실제로는, 영속성 컨텍스트를 통해서 엔티티를 영속화)
         System.out.println("board.id = " + board.getId());	// 저장된 데이터(ROW)의 새로 생성된 ID 컬럼을 가져와서 출력
        }
    • @GeneratedValue(startegy = GenerationType.SEQUENCE)

      • DB 시퀀스를 사용해서 기본 키 할당 (ORACLE, H2 데이터베이스) → DB에 의존 O
      • 유일한 값을 순서대로 생성하는 DB 기능
      • 선(식별자)조회 후(Entity)저장
      // 선언방식
      @Entity
      // sequenceName 속성을 이용하여, DB에서 생성한 "BOARD_SEQ"와 매핑
      @SequenceGenerator(
         name = "BOARD_SEQ_GENERATOR",
         sequenceName = "BOARD_SEQ", //매핑할 데이터베이스 시퀀스 이름
         initialValue = 1, allocationSize = 1)
      public class Board {
         @Id
         @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BOARD_SEQ_GENERATOR") 	// BOARD_SEQ_GENERATOR라는 시퀀스 생성기를 등록
         private Long id;
         ...
      }
      // 사용 방식
      private static void logic(EntityManager em) {
         Board board = new Board();
         em.persist(board);		// em.persist() 실행시, DB 시퀀스를 사용해서 ID를 조회하고, 조회한 ID를 엔티티에 세팅한 후 DB에 저장
         System.out.println("board.id = " + board.getId());
       }
    • @GeneratedValue(startegy = GenerationType.TABLE)

      • 키 생성 전용 테이블을 하나 만들고, 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터 베이스 시퀀스를 흉내냄 → DB에 의존 X
      • 테이블을 사용하므로, 모든 DB 사용 가능
      • 시퀀스 대신에 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작방식이 동일함
      // 선언 방식
      @Entity
      // @TableGenerator를 사용해서, 테이블 키 생성기를 등록
      @TableGenerator(
       name = "BOARD_SEQ_GENERATOR",
       table = "MY_SEQUENCES",		// MY_SEQUENCES 테이블을 키 생성용 테이블로 매핑
       pkColumnValue = "BOARD_SEQ", allocationSize = 1)
      public class Board {
       @Id
       @GeneratedValue(strategy = GenerationType.TABLE,
       generator = "BOARD_SEQ_GENERATOR")  // "BOARD_SEQ_GENERATOR" 라는 이름의 테이블 키 생성기를 등록
       private Long id
      // 사용 방식
      private static void logic(EntityManager em) {
       Board board = new Board();
       em.persist(board);
       System.out.println("board.id = " + board.getId());
      }
    • AUTO 전략 : @GeneratedValue(startegy = GenerationType.AUTO)

      • 선택된 DB 에 따라 JPA 가 IDENTITY, SEQUENCE, TABLE 전략 中 하나를 자동으로 선택
      • DB 를 변경해도 코드를 수정할 필요 없다는 장점
      • @GeneratedValue.strategy 의 기본값은 AUTO 이므로, strategy 속성을 사용하지 않아도 무방
      • 키생성전략이 정해지지 않은 초기 단계 or 프로토타입 개발시 이용하면 편리하다
      // 선언 방식
      @Entity
      public class Board {
         @Id
         @GeneratedValue(strategy = GenerationType.AUTO)
         private Long id;
         ...
      }

4) @Column

@Column
private String name;

(1) 정의

객체 필드를 테이블 컬럼과 매핑

(2) 속성

  • name
    - 필드와 매핑할 테이블의 컬럼 이름 지정
    - default 는 필드이름으로 대체

  • insertable
    - true : 엔티티 저장시 필드값 저장
    - false : 필드값이 저장되지 않음

    //Entity
    @Entity(name="user2")
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        @Id
        @GeneratedValue
        private Long id;
        // 필드값이 저장되지 않음 -> User 엔티티의 name 컬럼에 "test"를 입력해도 DB에는 값이 들어가지 않는다.
        @Column(insertable = false)	
        private String name;
        private String age;
    }
    
    //Service
    @Service
    @RequiredArgsConstructor
    public class TestService {
        private final EntityManager em;
        @Transactional
        public void test() {
            User user = User.builder()
                    .age("12")
                    .name("test")
                    .build();
            em.persist(user);		// em.persist 로 user 호출
        }
    }
  • updatable
    - true : 엔티티 수정시 값이 수정
    - false : 엔티티 수정시 값이 수정 되지 않음

    //Entity
    @Entity(name="user2")
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @Setter
    public class User {
        @Id
        @GeneratedValue
        private Long id;
        // 엔티티 수정시 값이 수정 되지 않음 -> User 엔티티 name 컬럼에 "test"를 입력하고 "change test"로 변경해도 변경값이 적용되지 않는다.
        @Column(updatable = false)		
        private String name;
        private String age;
    }
    
    //Service
    @Service
    @RequiredArgsConstructor
    public class TestService {
        private final EntityManager em;
        @Transactional
        public void test() {
            User user = User.builder()
                    .age("12")
                    .name("test")
                    .build();
            em.persist(user);		// em.persist 로 user 호출
            user.setName("change test");
        }
    }
  • table : 하나의 엔티티를 두 개 이상의 테이블에 매핑할 때 사용

  • nullable
    - null값 허용 여부 설정
    - false : not null 제약 조건

    @Entity(name="user2")
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @Setter
    public class User {
        @Id
        @GeneratedValue
        private Long id;
        @Column(nullable = false)
        private String name;
        @Column(nullable = true)
        private String age;
    }
  • unique : 컬럼에 유니크 제약조건 부여

    @Entity(name="user2")
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @Setter
    public class User {
        @Id
        @GeneratedValue
        private Long id;
        @Column(unique = true)
        private String name;
        @Column(unique = false)
        private String age;
    }
  • columnDefinition : 데이터베이스 컬럼 정보를 직접 부여

    @Entity(name="user2")
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @Setter
    public class User {
        @Id
        @GeneratedValue
        private Long id;
        @Column(unique = true)
        private String name;
        @Column(columnDefinition = "VARCHAR(15) NOT NULL")
        private String age;
    }

  • length
    - 문자 길이 제약조건
    - String 타입일 때 사용

    @Entity(name="user2")
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @Setter
    public class User {
        @Id
        @GeneratedValue
        private Long id;
        @Column(length = 11)
        private String name;
        @Column(columnDefinition = "VARCHAR(15) NOT NULL")
        private String age;
    }

  • precision, scale
    - BigDecimal 타입에서 사용 (Java 에서 숫자를 정밀하게 저장/표현할 수 있는 객체)
    - precision : 소수점을 포함한 전체 자릿수 설정
    - scale : 소수의 자릿수

5) @Access

@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
    @Id			// @Access를 설정하지 않으면, 기본키를 설정하는 @Id의 위치를 기준으로 접근 방식 설정
    @GeneratedValue
    private Long id;
}
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
@Access(AccessType.FIELD)
public class User {
    @Id
    @GeneratedValue
    private Long id;
}

(1) 정의

JPA가 엔티티 데이터에 접근하는 방식을 지정

(2) 속성

  • AccessType.FILED
    - 필드에 직접 접근
    - 필드 접근 권한이 private여도 접근 가능

    @Entity(name = "user2")
    @Table(name = "user3")
    @Getter
    @Setter
    @Access(AccessType.FIELD)
    public class User {
        @Id
        @GeneratedValue
        private Long id;
    }
  • AccessType.PROPERTY : getter(접근자)를 통해 접근

    @Entity(name = "user2")
    @Table(name = "user3")
    @Setter
    @Access(AccessType.PROPERTY)
    public class User {
    
        @GeneratedValue
        private Long id;
    
    		  // getter 에 @id 를 설정
        // @Id가 getter에 위치하는 경우, @Access 생략 가능
        @Id
        public Long getId() {
            return id;
        }
    }
  • 필드 접근과 프로퍼티 접근을 혼합해서!

    //Entity
    @Entity(name = "user2")
    @Table(name = "user3")
    @Getter
    @Setter
    public class User {
        @Id
        @GeneratedValue
        private Long id;
    
        @Transient
        private String name;
    	
        // PROPERTY 를 통해, getter의 fullName을 column으로 지정
        @Access(AccessType.PROPERTY)
        public String getFullName() {
            return name + " hello";
        }
        protected void setFullName(String firstName) { }
    }
    
    //Service
    @Service
    @RequiredArgsConstructor
    public class TestService {
        private final EntityManager em;
        @Transactional
        public void test() {
            User user = new User();
            user.setName("aaa");
            em.persist(user);		// em.persist 로 user 호출
        }
    }

6) @Enumerated

//Enum 클래스
public enum RoleType {
    ADMIN, USER
}

//Entity
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    @Enumerated(value = EnumType.ORDINAL)	// ADMIN의 순서인 0이 저장됨
    private RoleType ordinal;
    @Enumerated(value = EnumType.STRING)	// 문자열 자체가 저장됨
    private RoleType string;
}

//Service
@Service
@RequiredArgsConstructor
public class TestService {
    private final EntityManager em;
    @Transactional
    public void test() {
        User user = new User();
        user.setName("test");
        user.setOrdinal(RoleType.ADMIN);
        user.setString(RoleType.ADMIN);
        em.persist(user);		// em.persist 로 user 호출
    }
}

(1) 정의

자바 enum 타입을 매핑

(2) 속성

  • value
    - EnumType.ORDINAL : enum 순서를 DB 에 저장
    - EnumType.STRING : enum 이름을 DB 에 저장

(3) 주의점

ADMIN, USER 사이에 enum 이 하나 추가되면, USER가 순서상 2번이 된다.

하지만 DB에서는 기존 번호 USER를 1로 저장했기 때문에 문제가 발생할 수 있으므로
되도록이면 EnumType.STRING 사용을 권장

7) @Temporal

//Entity
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    @Enumerated(value = EnumType.ORDINAL)
    private RoleType ordinal;
    @Enumerated(value = EnumType.STRING)
    private RoleType string;
    @Temporal(value = TemporalType.DATE)
    private Date date;
    @Temporal(value = TemporalType.TIME)
    private Date time;
    @Temporal(value = TemporalType.TIMESTAMP)
    private Date timeStamp;
}

//Service
@Service
@RequiredArgsConstructor
public class TestService {
    private final EntityManager em;
    @Transactional
    public void test() {
        User user = new User();
        Date date = new Date();
        user.setName("test");
        user.setOrdinal(RoleType.ADMIN);
        user.setString(RoleType.ADMIN);
        user.setTime(date);
        user.setDate(date);
        user.setTimeStamp(date);
        em.persist(user);		// em.persist 로 user 호출
    }
}

(1) 정의

날짜 타입을 매핑

(2) 속성

  • value
    - TemporalType.DATE : 날짜, DB date 타입과 매핑 (예 : 2020-02-12)
    - TemporalType.TIME : 시간, DB time 타입과 매핑 (예: 12:12:12)
    - TemporalType.TIMESTAMP : 날짜와 시간 DB timestamp타입과 매핑 (예 : 2020-02-12 12:12:12)

(3) 주의점

실무에선 잘 사용 X

8) @Lob

//Entity
@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    @Enumerated(value = EnumType.ORDINAL)
    private RoleType ordinal;
    @Enumerated(value = EnumType.STRING)
    private RoleType string;
    @Temporal(value = TemporalType.DATE)
    private Date date;
    @Temporal(value = TemporalType.TIME)
    private Date time;
    @Temporal(value = TemporalType.TIMESTAMP)
    private Date timeStamp;
    @Lob
    private String stringLob;
    @Lob
    private Integer integerLob;
}

//Service
@Service
@RequiredArgsConstructor
public class TestService {
    private final EntityManager em;
    @Transactional
    public void test() {
        User user = new User();
        Date date = new Date();
        user.setName("test");
        user.setOrdinal(RoleType.ADMIN);
        user.setString(RoleType.ADMIN);
        user.setTime(date);
        user.setDate(date);
        user.setTimeStamp(date);
        user.setStringLob("hello");
        user.setIntegerLob(2);
        em.persist(user);		// em.persist 로 user 호출
    }
}

Mysql에서의 결과

integerLob 은 LONGBLOB 으로 매핑
stringLob 은 LONGTEXT 으로 매핑

(1) 정의

필드 타입이 문자열 : CLOB
나머지 : BLOB을 매핑

(2) 주의점

실무에선 잘 사용 X

9) @Transient

@Entity(name = "user2")
@Table(name = "user3")
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    @Enumerated(value = EnumType.ORDINAL)
    private RoleType ordinal;
    @Enumerated(value = EnumType.STRING)
    private RoleType string;
    @Temporal(value = TemporalType.DATE)
    private Date date;
    @Temporal(value = TemporalType.TIME)
    private Date time;
    @Temporal(value = TemporalType.TIMESTAMP)
    private Date timeStamp;
    @Lob
    private String stringLob;
    @Lob
    private Integer integerLob;

    //임시 사용
    @Transient
    private String trans;
}

@Transient를 단 trans필드는 DB컬럼에 추가되지 않는다.

(1) 정의

  • @Transient 어노테이션을 붙인 필드는 DB에 저장 X / 조회 X
  • 객체에 임시로 값을 보관하고 싶을 때 사용

참고: [JPA] 2. 엔티티 매핑 @어노테이션 정리/예제
참고: 4장 엔티티 매핑
참고: [Spring JPA] JPA 엔티티 매핑(Entity Mapping)

profile
개발자로 거듭나기!

0개의 댓글