JPA를 사용하면 SQL문이 아닌 객체로 직접 작업할 수 있다.
JPA는 데이터 베이스 스키마를 자동으로 생성하는 옵션을 제공한다.
엔티티 매핑은 일반적으로 어노테이션을 통해 정의된다.
- 객체와 테이블 매핑: @Entity, @Table
- 필드와 컬럼 매핑: @Column
- 기본 키 매핑: @Id
- 연관관계 매핑: @ManyToOne, @JoinColumn
DB에 유지되어야하는 클래스에는 @Entity 어노테이션을 달아야 한다.
@Entity가 있으면 JPA가 관리하는 클래스이다.
@Entity가 없으면 JPA와 관련없는 클래스이다.
주의 사항:
1. 반드시 기본키 생성자 @Id는 필수
2. final, enum, interface inner 클래스의 사용 X
3. DB에 저장할 필드엔 final사용 X
기본적으로 테이블 이름은 클래스 이름에 해당한다.
테이블 이름을 변경하고 싶을 때에는 @Table 어노테이션을 추가해 변경한다.
@Table(name="TABLE_NAME")
JPA는 애플리캐이션이 시작될 때 엔티티를 DDL문으로 변환해 DDL을 자동으로 생성해준다.
사용하는 데이터베이스에 따라 적절한 DDL을 생성한다.
Entity 클래스 내에 String name이 있다고 가정해보자.
private String name;
오라클 DB를 쓰면 varchar2로 변환되고 MYSQL을 쓰면 varchar로 변환 되어야하는데, JPA는 이를 자동으로 변환해준다.
생성할 DDL명령을 제어하기 위해 몇가지 JPA는 몇가지 옵션을 제공한다.
hibernate.hbm2ddl.auto
1. create: 기존테이블 삭제 후 다시 생성
2. create-drop: create와 같으나 종료시점에 테이블 drop
3. update: 테이블 변경만 반영
4. validate: 엔티티와 테이블이 정상 매핑되었는지만 확인
5. none 사용하지 않음
DDL명령 옵션사용시 주의사항:
운영장비에는 절대 create, create-drop, update를 사용하면 안된다.
운영장비에 사용시 운영중인 DB의 column들의 값에 문제가 생길 수 있기 때문이다.
DDL 생성 기능에 제약조건을 추가할 수 있다.
제약조건: 이름은 필수 10자 초과X
@Column(nullable = false, length =10)
private String name;
유니크 제약조건은 @Column에 추가할 수도 있지만,
보통 @UniqueConstaint를 사용해 @Table에 추가한다.
@Entity
@Table(uniqueConstraints = {@UniqueConstraint(name ="NAME_AGE_UNIQUE",
columnNames = {"NAME", "AGE"} )})
public class Member{...}
DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.
name
기본값: 객체의 필드 이름
필드와 매핑할 테이블의 칼럼 이름
@Column(name = "name")
inserttable, updatable
기본값: TRUE
등록, 변경 가능 여부를 판단한다.
@Column(insertable = false)
nullable(DDL)
null 값의 허용 여부를 설정한다.
DDL 생성시 not null의 제약조건이 붙는다.
@Column(nullable = false)
unique(DDL)
@Table의 uniqueConstraints와 같다.
컬럼에 간단히 유니크 제약조건을 걸 때 사용한다.
@Column(unique = true)
columnDefinition(DDL)
기본값: 필드 자바 타입과 DB방언 정보 사용
데이터베이스 컬럼정보를 직접줄 수 있다.
@Column(columnDefinition = "EMPTY")
length(DDL)
기본값: 255
문자 길이 제약조건으로, String 타입만 사용한다.
@Column(length = 10)
precision,scale(DDL)
기본값: precision=19, scale=2;
BigDecimal 타입에서 사용한다.
precision은 소수점을 포함한 전체 자릿수를 scale은 소수의 자릿수다.
double, float 타입에는 적용되지 않는다.
아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용한다.
@Column(precision = 30, scale = 5)
Enum 타입을 매핑할 때 사용한다.
value
기본값: EnumType.ORDINAL
EnumType.ORDINAL: enum 순서를 데이터 베이스에 저장
EnumType.STRING: enum 이름를 데이터 베이스에 저장
@Enumerated(EnumType.STRING)
주의사항:
ORDINAL은 사용하면 안된다.
다음은 Member 엔티티 클래스와, RoleType Enum클래스다.
@Entity
@Getter @Setter
public class Member {
@Id
private Long id;
@Enumerated(EnumType.ORDINAL)
private roleType roleType;
}
@Getter @Setter
public enum RoleType {
TYPE1,TYPE2
}
다음은 Member A,B,C가 DB에 저장되는 상황이다.
Member A = new Member();
Member B = new Member();
Member C = new Member();
A.setId(1);
B.setId(2);
C.setId(3);
A.setRoleType(RoleType.TYPE1);
B.setRoleType(RoleType.TYPE1);
C.setRoleType(RoleType.TYPE2);
em.persist(A)
em.persist(B)
em.persist(C)
em.flush();
A와 B의 roleType은 TYPE1으로 1이 저장되고,
C의 roleType은 TYPE2으로 2가 저장된다.
그 다음 Enum클래스를 다음과 같이 변경한다고 생각해보자.
@Getter @Setter
public enum RoleType {
TYPE0,TYPE1,TYPE2
}
그리고 다음의 코드를 실행하면 어떤 일이 일어날까?
Member D = new Member();
D.setId(4);
D.setRoleType(RoleType.TYPE0);
em.persist(D)
em.flush();
C의 roleType은 TYPE0으로 1이 저장된다.
DB에는 A와B roleType은 1로 저장되어있어 TYPE0으로 판단된다.
A,B는 TYPE1이지만, A,B,C는 같은 TYPE0이 되는 문제가 생긴다.
따라서 EnumType.STRING만 사용하는 것이 좋다.
DB에 대형 객체를 저장하기 위한 가변 길이 데이터 유형을 나타냅니다.
@Lob에는 지정할 수 있는 속성이 없다.
데이터 유형
CLOB: 매핑하는 필드 타입이 문자면 CLOB
BLOB: 나머지
필드 매핑을 하지않고, 데이터베이스에 저장하기 싫을 때 사용한다.
메모리상에 임시로 어떤 값을 저장하고 싶을 때 사용한다.
Entity 클래스는 반드시 기본키를 가져야한다.
JPA는 @Id를 통해 기본키를 나타낸다.
기본키를 생성하는 방법으로 두가지가 있다.
직접 생성: @Id
자동 생성: @Id @GeneratedValue
@GeneratedValue를 이용한 기본키 생성 전략
1. AUTO
2. IDENTITY
3. SEQUENCE
4. TABLE
AUTO
자동생성, 기본값
IDENTITY
기본 키 생성을 DB에 위임한다.
prisist() 시점에 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회한다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
JPA의 기본 키를 통해 1차 캐시에 접근하기 때문에 IDENTITY 전략은 em.persist()시점에 em.flush()를 한다.
SEQUENCE
DB 시퀀스는 유일한 값을 순서대로 생성하는 특별한 오브젝트이다.
DB의 시퀀스 테이블을 사용해 기본키를 생성한다.
DB가 DB 시퀀스를 지원하는 경우 시퀀스를 사용한다. 지원되지 않으면 TABLE전략으로 전환한다.
시퀀스 이름을 사용자가 정의하기 위해서 @SequenceGenerator를 사용한다.
@Entity
@SequenceGenerator(
name = "SEQ_GENERATOR",
sequenceName = "SEQ"//매핑할 데이터베이스 시퀀스 이름
initialValue = 1, allocationSize = 1)
public class Member{
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "SEQ_GENERATOR")
private long id;
}
키 생성 전용 테이블을 하나 만들어 DB시퀀스를 흉내내는 전략이다.
모든 DB에 사용이 가능하지만, 성능 문제가 있다.
<강의/ 책>
1. 자바 ORM 표준 JPA 프로그래밍 - 기본편
본 글은 김영한 님의 강의와 책을 보고 쓴 글입니다.