[SpringBoot-JPA 기본편] 자바 ORM 표준 JPA 프로그래밍 - 기본편: 4. 엔티티 매핑
강의 출처:https://www.inflearn.com/course/ORM-JPA-Basic#curriculum
해당 강의는 Inflearn에 등록된 김영한님의 Spring Boot 강의입니다.
1. 객체와 테이블 매핑
@Entity
@Entity
가 붙은 클래스는 JPA가 관리하고, 이를 엔티티
라 한다.
- 기본 생성자 필수(파리미터가 없는 public 또는 protected 생성자)
- final 클래스, enum, interface, inner 클래스는 사용 할 수 없다.
- 저장할 필드에 final 사용 하면 안된다.
@Entity
@Table(name = "USER") //Table 명을 User로 변경하고 싶으면 이렇게,MEMBER그대로 쓰려면 지우기
public class Member {
@Id
private Long id;
private String name;
...
}
2. 데이터베이스 스키마 자동 생성
운영장비나 배포시에는 **create
가 아니라 반드시 `none`**으로 해야한다.
왜냐하면 create는 기존 테이블 삭제 후 다시 생성을 하기에 테스트 하기에는 좋으나 운영할 때 쓰면 절대 안된다!
DDL(CREATE, ALTER, DROP, TRUNCATE)을 자동 생성할 때만 영향을 주고 JPA의 실행 로직에는 영향을 주지 않는다.
//DDL 생성기능은 JPA 로직에는 영향X
@Column(name="USERNAME",unique = true,length = 10)//컬럼명은 name,unique,길이10개 특성 부여
private String name;
3. 필드와 컬럼 매핑
- 매핑 annotation
Annotation | 설명 |
---|---|
@Column | 컬럼 매핑 |
@Temporal | 날짜 타입 매핑 |
@Enumerated | enum 타입 매핑 |
@Lob | BLOB, CLOB 매핑 |
@Transient | 특정 필드를 컬럼에 매핑하지 않음(매핑 무시) |
위의 매핑 annotation
을 적용해보자. 그전에 회원 객체 필드의 수정을 읽어보자.
저번시간에 member
객체에 정의한 변수
name 필드
는 사실 추후 엔티티
의 컬럼(속성)
이 된다.
우선 enumType 클래스
에 회원을 관리자 일반회원으로 구분 하도록 정의한다.
(아까도 언급 했듯이 enum 클래스에는 @Entity 를 사용하지 못한다.)
public enum RoleType {
USER,ADMIN
}
@Entity //jpa가 관리하는 객체로 annotation
public class Member {
@Id
private Long id;
//컬럼명은 name,not null 제약조건,varchar(10),
@Column(name="name",nullable = false,length = 10)
private String name;
private Integer age;
//@Enumerated: enum타입을 매핑하때 사용.
@Enumerated(EnumType.STRING) //★★★반드시 ORDINARY형으로 쓰면 안된다.
private RoleType roleType; //일반사용자,관리자로 회원을 구분
//@Temporal은 날짜 매핑
@Temporal(TemporalType.TIMESTAMP)
private Date createdDate; //생성일자
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate; //마지막 수정 일자
//위의 @Temporal은 과거사용. 요즘은 그냥 자바에서 밑과 같이 지원함.
private LocalDate testLocalDate; //연,월
private LocalDateTime testLocalTime; //연,월,일
// @Lob 애노테이션은 엔터티 클래스의 필드가 대형 객체를 뜻함.
// 문자열이나 바이트 배열과 같은 큰 데이터를 매핑할때 사용(clob:문자열,blob:바이트)
@Lob
private String description;
//@Transient은 변수나 객체는 매핑 하기 싫다고하는 annotation.
//실험이나 특정 로직에서 테스트 용으로 사용.(DB와 상관없게 해줌)
@Transient
private int temp;
//JPA 내부적으로 reflextion을 쓰므로 동적으로 객체 생성이 해야한다.
//따라서 아무것도 없는 기본 생성자를 먼저 만들어야 한다.
public Member() {
}
위 코드의 주석을 총 5가지의 보면 객체의 필드를 컬럼(속성)으로 매핑 하는 과정을 서술 했다.
(주석 설명이 제일 중요하므로 꼭 한번 읽어보시길 바랍니다.)
4. 기본 키 매핑
바로 위에서는 객체
의 필드
와 데이터 베이스
의 컬럼
(속성)을 매핑
하는 과정을 봤다면, 이번에는 기본키 매핑
이다. 다음은 기본키
에 대한 정리이다.
기본키( primary key )는 데이터베이스에서 각 행(레코드)을 고유하게 식별하는데 사용되는 필드(열)를 말한다.
테이블에는 반드시 하나의 기본키가 있어야 하고, 이 키는 그 테이블의 모든 행에서 유일한 값을 가져야 한다. 기본키로 지정된 필드는 NULL 값을 가질 수 없고, 중복된 값을 가질 수 없다.
기본키 매핑 방법
기본키의 자동생성은 위의 총 4가지 타입으로 할 수 있다.
@GeneratedValue(strategy=GenerationType.원하는 타입)
위의 @GeneratedValue
만 쓰면 자동으로 AUTO
형식이다.
대부분 전략 속성에서 중요한건 allocationSize
이다. 시퀀스 한 번 호출에 증가하는 수 (성능 최적화
에 사용됨)
데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값 을 반드시 1로 설정해야 한다.
데이터베이스에서 시퀀스 값을 생성할 때마다 데이터베이스와의 통신이 필요한데, 이 과정은 상대적으로 비용이 많이 들고 시간이 걸릴 수 있다. allocationSize를 사용하여 시퀀스 값을 미리 일정량만큼 할당하면, JPA 구현체는 데이터베이스에 접근하는 횟수를 줄일 수 있다. 이는 특히 많은 양의 데이터를 빠르게 처리해야 하는 상황에서 데이터베이스와 애플리케이션 사이의 부하를 크게 줄여줄 수 있다.
예를들면, 사용자는 주문에서 상품을 40개씩 주문 한다고 치자. 그러면 주문 상품 테이블의 기본키를 갖는 행은 40개가 증가할텐데, 이때 1개씩 데이터 베이스에 등록하는게 아니라 할당량을 미리 50으로 설정해서 시스템은 데이터 베이스에 시퀀스를 50개를 한번에 처리하게된다. 이로인해 속도도 훨씬 빠르고 쿼리가 훨씬 덜 나가 성능 측면에서 좋다. 요즘은 네트워크 인프라가 워낙 잘 되어 있다보니 수십~수백개로 설정해도 끄덕없으나 기본값이 50으로 설정된 이유는 대부분의 상황에서 균형 잡힌 성능 최적화를 제공한다고 보았기에 JPA 설계자들이 설정한 것 이다.
다음은 SequenceGenerator와 Table 전략이다. 둘다 PK를 증가시키는 방법 중 하나이다.
Member 클래스
@SequenceGenerator(
name="MEMBER_SEQ_GENERATOR", //순차증가시킬 생성기 이름
sequenceName = "MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름.
initialValue = 1, allocationSize = 50
//초기값1
// allocationSize : 시퀀스 한 번 호출에 증가하는 수:50
//미리 DB에 50개를 올려놓고, 메모리상에서는 1개씩 증가(성능 최적화에 사용됨)
)
/*
@TableGenerator(
name = "MEMBER_SEQ_GENERATOR", // 테이블 생성 이름
table = "MY_SEQUENCES", //테이블 이름
pkColumnValue = "MEMBER_SEQ", allocationSize = 1 //시퀀스 열명
)*/
public class Member {
//@GeneratedValue(strategy = GenerationType.IDENTITY): 데이터베이스 방언에 따라 자동생성
//GenerationType.SEQUENCE: 순차적으로->H2,ORACLE에서 사용
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "MEMBER_SEQ_GENERATOR")
private Long id;
다음은 권장하는 식별자 전략에 대한 설명이다.
기본키
는 Long
형으로 작성하고 고유해야한다. 만약 타입이 다르면 에러가 발생할 수 있다. (ex: long vs Long)
다음시간 부터는 회원 객체 뿐만아니라 더 많은 객체들과 연관관계 매핑을 해보겠다.