JPA 필드와 컬럼 매핑 상세 옵션과 주의사항
1. insertable, updatable
insertable과 updatable 옵션은 엔터티의 필드가 데이터베이스에 어떻게 반영될지를 결정하며, 기본 값은 true로 필드가 기존 DB와 다르거나, 기존에 값을 수정을 막을 수 있다.
예제
@Column(insertable = true, updatable = true)
private String name;
@Column(insertable = true, updatable = false)
private String createdAt;
@Column(insertable = false, updatable = true)
private String updatedAt;
name: 삽입과 업데이트가 모두 가능하다.
createAt: 처음 삽입할 때만 가능하며 업데이트는 불가능하다.
updatedAt: 삽입이 불가능하며 업데이트만 가능하다.
2. nullable (DDL)
nullable 옵션을 사용하면 NOT NULL 제약 조건이 생성된다.
3. unique (DDL)
이를 사용하면 unique 조건이 걸리게 된다.
하지만 unique 제약 조건을 생성시 컬럼 명이 아래와 같이 이상한 이름으로 된다.
alter table Member
add constraint UK_ektea7vp6e3low620iewuxhlq unique (name)
때문에 @Table 에서 uniqueConstraints로 사용하는게 훨씬 유용하다.
4. length (DDL)
length 옵션은 문자열 필드의 최대 길이를 지정하며, 기본값은 255이다.
5. precision, scale (DDL)
이 옵션은 BigDecimal 타입혹은 BigInteger에서 사용한다.
precision은 소수점을 포함한 전체 자릿수를 ,scale은 소수의 자리수이다.
double, float에는 적용되지 않으며 정밀한 소수를 다루어야할 때 사용한다.
6. @Enumerated
@Enumerated는 EnumType.STRING, EnumType.ORDINAL 이 있다.
EnumType.ORDINAL은 타입을 숫자로 저장한다.
여기서 EnumType.ORDINAL는 절대 사용하지 않도록 한다.
만약 Enum 클래스에서 순서가 바뀌어 앞에 새로운 형태의 enum값이 생성시 다 밀리게 되므로, 값이 이상해진다.
결론: 무조건 EnumType.STRING를 사용해야한다.
7. @Lob
Lob에는 지정할 수 있는 속성이 없다.
@Lob은 큰 객체를 저장할 때 사용된다. 문자열 필드는 CLOB으로, 그 외 필드는 BLOB으로 매핑된다.
8. @Transient
엔티티에는 존재하나, 데이터베이스에는 반영하지 않을 필드에 사용한다.
JPA 기본키 생성 전략
1. 기본 키 매핑 (@Id)
기본 키는 엔티티를 유일하게 식별하는 역할을 한다. JPA에서는 '@Id' 애노테이션을 사용하여 기본키를 매핑한다.
@Id
private Long id
2. 직접 할당 전략
'@Id' 만 사용하여 기본 키를 직접 할당할 수 있다. 예를 들어, "KOREA_"와 조합하여 기본키를 생성할 수 있다.
@Id
private String id; // 직접 할당을 위해 String 타입을 사용
public void setId(String id) {
this.id = "KOREA_" + id; // "KOREA_" 접두어를 붙여서 id를 설정
}
3. 자동 생성 전략 (GeneratedValue)
- AUTO
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
AUTO로 설정해놓으면 DB의 방언에 맞추는 기본키 생성 전략이다.
- Identity
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
기본 키 생성을 데이터베이스에 위임한다.
identity는 'INSERT' 쿼리를 날린 후에 ID 값을 알 수 있다.(db에 들어가 봐야 id값을 알 수 있다.)
하지만 1차 캐시에서는 @id를 필수로 갖고 있어야하는데, 어떻게 하는 걸까?
그래서 다른 편법을 쓰는데, 유일하게 em.persist하는 순간 Insert query가 날라간다. 아래에서 자세히 다룬다.
- Sequence
@SequenceGenerator(
name = "MEMBER_SEQ_GENERATOR",
sequenceName = "MEMBER_SEQ", // 매핑할 데이터베이스 시퀀스 이름
initialValue = 1, allocationSize = 50
// 50개씩 미리 땅겨서 갖고 옴
)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@Column(name = "name")
private String username;
id는 무조건 Long으로 설정하는 것이 좋다.
int는 10억 넘어가면 초기화가 되기 때문에 오버플로우가 발생한다.
sequence를 따로 설정하기 위해 다음과 같이 생성한다.
50개씩 미리 갖고오기 때문에 db에서 call next value를 해도 성능 문제가 줄어든다.
Identity 전략과 Sequence 전략의 차이점 및 동작 방식
Identity 전략
특징: 기본 키 생성을 데이터베이스에 위임한다.
적용 DB: 주로 MySQL, PostgreSQL에서 사용된다.
동작 방식: INSERT 쿼리를 실행한 후에 데이터베이스에서 ID 값을 가져온다.
즉, 레코드가 실제로 데이터베이스에 삽입된 후에만 ID 값을 알 수 있다.
1차 캐시 문제: em.persist()를 호출하는 순간 INSERT 쿼리가 실행되고, 그 후에 ID 값이 엔터티에 할당된다.
이는 JPA가 1차 캐시에서 엔터티를 관리하기 위해 필요한 작업이다.
Sequence 전략
특징: 데이터베이스의 시퀀스 객체를 사용하여 기본 키 값을 생성한다.
적용 DB: 주로 Oracle, PostgreSQL에서 사용된다.
동작 방식: em.persist()를 호출하기 전에 미리 시퀀스에서 ID 값을 가져와 엔터티에 할당할 수 있다.
따라서 INSERT 쿼리가 실행되기 전에도 ID 값을 알 수 있다.
1차 캐시 문제: em.persist()를 호출하기 전에 ID 값이 이미 할당되므로, 1차 캐시에서 엔터티를 쉽게 관리할 수 있다.
요약
Identity 전략: em.persist()를 호출하면 INSERT 쿼리가 바로 실행되고, 그 후에 생성된 ID 값을 엔터티에 할당한다.
Sequence 전략: JPA가 em.persist() 호출 전에 미리 시퀀스를 조회하여 ID 값을 엔터티에 할당한다.
- Table
키 생성 전용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략이다.
장점: 모든 데이터베이스에 적용할 수 있다.
단점: 성능이 조금 떨어진다.
운영에서는 조금 관리하기 힘들다.
@Entity
@TableGenerator(
name = "MEMBER_SEQ_GENERATOR",
table = "MY_SEQUENCES",
pkColumnValue = "MY_SEQUENCES", allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
4. 권장하는 식별자 전략
기본 키 제약 조건: null 아니어야하며, 유일해야하고, 변하면 안된다.
권장 전략: Long형 + 대체키 + 키 생성전략 사용
'JPA > ORM 표준 JPA' 카테고리의 다른 글
[ORM 표준 JPA] 7. 연관관계 매핑2 양방향 연관관계와 연관관계의 주인 (0) | 2023.09.23 |
---|---|
[ORM 표준 JPA] 6. 연관관계 매핑 1 (0) | 2023.09.23 |
[ORM 표준 JPA] 4. 엔티티 매핑1 - 객체와 테이블 매핑 (0) | 2023.09.18 |
[ORM 표준 JPA] 3. 영속성 관리 - 내부 동작 방식 (0) | 2023.09.16 |
[ORM 표준 JPA 프로그래밍] 2. JPA와 Hibernate: 데이터베이스와의 다리 역할 (0) | 2023.09.13 |