김영한 님의 자바 ORM 표준 JPA 프로그래밍을 읽고 정리한 내용입니다.
엔티티 매핑
JPA에서 실제 테이블에 연결하는 객체를 엔티티라고 부른다.
따라서 엔티티와 테이블을 정확히 매핑시켜 사용하는 것이 매우 중요하다.
아래는 매핑을 위한 대표적인 Annotation 목록이다.
- 객체와 테이블 매핑
@Entity
@Table
- 기본 키 매핑
@Id
- 필드와 컬럼 매핑
@Column
- 연관관계 매핑
@ManyToOne
@JoinColumn
@Entity
테이블과 매핑할 클래스엔 @Entity
가 반드시 붙어야 한다.
속성
- name (Default : 클래스명)
- entity에 사용할 이름
- 엔티티 중복은 허용되지 않는다.
- entity의 이름과 테이블 이름은 다른 개념이다.
주의사항
- 기본 생성자는 반드시 존재해야 하며 public/proteced 접근자를 가져야 한다.
- 자바는 기본 생성자를 만들지 않으면 빈 생성자를 자동으로 생성한다.
- 그러나 별도의 생성자를 정의할 경우 기본 생성자가 만들어지지 않는다.
- 그럴 땐 반드시 기본 생성자를 명시적으로 정의해야 한다.
- final, enum 클래스, 내부 클래스, 인터페이스엔 사용 불가능
- 저장할 필드에 final 사용 불가능
@Table
엔티티와 매핑할 테이블을 지정한다.
생략 시 엔티티 이름이 테이블 이름으로 사용된다.
@Table 속성
name (Default : 엔티티명)
- 매핑할 테이블 이름
catalog
- catalog 기능이 있는 DB에서 catalog 매핑
schema
- schema 기능이 있는 DB에서 schema 매핑
uniqueConstraints
- DDL 생성 시 유니크 제약조건 생성
- 복합 제약조건 생성 가능
- JPA의 스키마 자동 생성 기능을 사용하여 DDL을 만들 때에만 적용됨.
스키마 자동 생성하기
JPA는 엔티티와 테이블을 매핑하고 DB 스키마를 자동으로 생성한다.
Spring properties에 아래의 속성을 입력한다.
spring:
jpa:
hibernate:
ddl-auto: create
show-sql: true
ddl-auto 속성은 엔티티를 읽어 테이블을 자동으로 생성한다.
show-sql은 어플리케이션에서 JPA를 통해 사용한 SQL문을 로그로 뿌려주는 기능이다.
Entity 클래스 Member
가 정의되어 있다고 가정하고, Spring boot 어플리케이션을 실행한다면 아래와 같은 로그를 확인할 수 있다.
Hibernate: drop table MEMBER if exists
Hibernate: create table MEMBER ( ... )
drop을 먼저 실행하고 테이블을 생성했다.
ddl-auto 속성이 create인 경우 어플리케이션 시작 시 모든 테이블을 삭제하고 다시 만들기 때문에 drop을 실행한 것이다.
ddl-auto 옵션
- create
- 위의 예제처럼 테이블을 모두 삭제한 뒤 다시 생성한다.
- DROP → CREATE
- create-drop
- create 속성을 포함한다.
- 애플리케이션 종료 시 생성한 DDL도 제거한다.
- DROP → CREATE → DROP
- update
- DB 테이블과 엔티티 매핑정보를 비교한다.
- 변경 사항만 수정한다.
- validate
- DB 테이블과 엔티티 매핑 정보를 비교한다.
- 변경 사항이 있는 경우 경고를 발생시키고 어플리케이션을 실행시키지 않는다.
- none
- 자동 생성 기능을 사용하지 않는다.
ddl-auto 옵션 전략
- 운영 서버에서는 DDL 수정 옵션을 절대 사용하지 않는다
- create, create-drop, update 절대 금지
- 개발 초기 단계
- create, update 사용
- 초기화 상태로 자동화된 테스트를 진행하는 환경 / CI 서버
- create, create-drop 사용
- 테스트 서버
- update, validate 사용
- 스테이징/운영 서버
- validate, none 사용
기본 키 매핑
@Id
를 사용하면 테이블의 기본 키를 매핑할 수 있다.
기본 키 할당 전략
직접 할당
애플리케이션에서 직접 할당한다.
Board board = new Board(); board.setId(1); boardRepository.save(board);
자동 생성
@GeneratedValue
를 사용하여 키를 자동으로 생성한다.strategy 옵션을 활용하여 자동 생성 전략을 정의할 수 있다.
GenerationType.IDENTITY
DB에 위임하는 방법이다.
MySQL의 AUTO_INCREMENT와 같은 기능을 수행한다.
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
GenerationType.SEQUENCE
유일한 값을 순서대로 생성하는 전략으로, DB에서 지원해야 가능하다.
오라클, PostgreSQL, DB2, H2에서 사용 가능하다.
@Entity @SequenceGenerator( name = "BOARD_SEQ_GENERATOR", sequenceName = "BOARD_SEQ", initialValue = 1, allocationSize = 1) public class Board { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BOARD_SEQ_GENERATOR") private Long id; }
@SequenceGenerator
- name : 식별자 생성기 (필수)
- sequenceName : DB에 등록된 시퀀스 이름
- initialValue : 시퀀스 DDL을 생성할 때 시작할 수를 정함 (Default 1)
- allocationSize : 시퀀스 한 번 호출에 증가하는 수
- catalog, schema : DB의 catalog, schema 이름
GenerationType.TABLE
키 생성 전용 테이블을 만들어 여기에 이름과 값으로 사용할 컬럼을 만든다.
위의 시퀀스를 흉내내는 전략이다. 모든 DB에서 사용 가능하다.
테이블
@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; }
@TableGenerator
- name : 식별자 생성기 (필수)
- table : 키 생성 테이블명
- pkColumnName : 시퀀스 컬럼명
- valueColumnName : 시퀀스 값 컬럼명
- pkCOlumnValue : 키로 사용할 값 이름
- initialValue : 초기값 (Default 0)
- allocationSize : 시퀀스 한 번 호출에 증가하는 수
- catalog, schema : DB의 catalog, schema 이름
GenerationType.AUTO
- 선택한 데이터베이스의 방언에 따라 IDENTITY, SEQUENCE, TABLE 중 하나를 자동으로 선택한다.
- 오라클인 경우 SEQUENCE, MySQL인 경우 IDENTITY를 선택한다.
- 데이터베이스를 변경해도 코드 수정이 필요 없다는 장점이 있다.
필드와 컬럼 매핑
아래는 컬럼과 매핑되는 대표적인 Annotation의 종류이다.
@Column
- 일반적인 컬럼 매핑용
Enumerated
- enum 타입 매핑
@Temporal
- 날짜 타입 매핑
@Lob
- BLOB, CLOB 타입 매핑
@Transient
- 매핑하지 않는 필드 명시
@Access
- JPA가 엔티티에 접근하는 방식 지정
@Column
@Column
은 객체 필드를 테이블 컬럼과 매핑한다.
가장 일반적으로 사용된다.
아래는 속성 목록이다.
- name (Default 필드 이름)
- 테이블의 컬럼 이름
- insertable (Default true)
- 엔티티 저장 시 이 필드도 같이 저장
- false로 설정 시 이 필드를 DB에 저장하지 않음.
- updatable (Default true)
- 엔티티 수정 시 이 필드도 같이 수정
- false로 설정 시 DB 수정하지 않음.
- table
- 하나의 엔티티를 두 개 이상의 테이블에 매핑할 떄 사용
- nullable (Default true)
- false로 설정 시 이 필드에 NOT NULL 옵션 추가
- unique
- 유니크 제약조건 설정
- columnDefinition
- DB의 컬럼 정보를 직접 줄 수 있음.
- length
- 문자 길이 제한
- precision, scale
- BigDecimal, BigInteger 등에서 사용
- precision은 소수점을 포함한 전체 자리수를 명시한다
- scale은 소수의 자리수를 명시한다.
@Enumerated
enum 타입을 매핑할 때 사용한다.
enum 정의
enum LogType { CREATE, READ, UPDATE, DELETE }
enum 사용
// 필드 정의 @Enumerated(EnumType.STRING) private LogType logType; // 실제 사용 logType.setLogType(LogType.READ);
@Enumerated
의 속성은 value가 있다.
EnumType.ORDINAL
을 사용하면 enum 순서를 DB에 저장하고 EnumType.STRING
을 사용하면 enum 이름을 데이터베이스에 저장한다.
@Temporal
날짜 타입을 매핑할 때 사용한다. 생략 시 timestamp 형식으로 자동 저장된다.
옵션으로 형식을 정해주어야 한다.
- TemporalType.DATE
- 날짜 (2020-02-22) 저장
- DB의 date 타입과 매핑
- TemporalType.TIME
- 시간 (16:50:30) 저장
- DB의 time 형식에 매핑
- TemporalType.TIMESTAMP
- 날짜와 시간 (2020-02-22 16:50:30) 저장
- DB의 timestamp에 매핑
@Lob
@Lob
에는 속성을 정하지 않는다.
매핑 필드 타입이 문자면 CLOB, 나머지는 BLOB로 자동 설정된다.
@Transient
데이터베이스에 저장되지도 않고 불러올 수도 없다.
객체에 임시로 값을 저장하고자 할 때 사용하기 적합하다.
@Access
JPA가 엔티티 데이터에 접근하는 방식을 지정한다.
필드로 접근하기 (AccessType.FIELD)
- 객체 필드에 직접 접근하는 방식
프로퍼티로 접근하기 (AccessType.PROPERTY)
- getter 메소드에 접근하는 방식
사용 예시를 보면 쉽게 이해할 수 있다.
AccessType.FIELD
@Entity @Access (AccessType.FIELD) public class Member { @Id private Long id; @Column private String name; }
AccessType.PROPERTY
@Entity @Access (AccessType.PROPERTY) public class Member { private Long id; private String name; @Id public Long getId() { return id; } @Column public String getName() { return name; } }
같이 사용 (getter에 특별한 로직이 필요한 경우 유용)
@Entity public class Member { @Id private Long id; private String name; @Column public String getName() { return name; } }
'Java > JPA' 카테고리의 다른 글
JPA 사용 시 주의할 점 (1) | 2021.07.22 |
---|---|
[JPA] 다양한 연관관계 매핑 (0) | 2020.04.07 |
[JPA] 연관관계 매핑 기초 (1) | 2020.02.26 |
[JPA] EntityManager, 영속성 컨텍스트 (0) | 2020.02.17 |