Entity내에서 많이 사용할법한 기본 어노테이션을 정리.
정리할 어노테이션은 아래와 같다.
- @GeneratedValue
- @Table
- @Column
- @Transient
정리전 예제 환경은 아래와 같다.
- Intelli J
- SpringBoot 2.6.2
- Lombok
- Gradle 7.3.2
1. @GeneratedValue
@GeneratedValue는 JPA 기초 포스팅에서도 정리했지만 기본키 생성을 데이터베이스에게 위임해 id값을 따로 할당하지 않아도 데이터베이스가 자동으로 기본키를 생성해주도록 하는 어노테이션이다.
속성으로는 TABLE, SEQUENCE, IDENTITY, AUTO가 존재한다.
타입은 enum 클래스인 GenerationType에서 볼 수 있다.
사용은 아래와 같이 한다.
좀 더 자세한 사용법은 각 전략을 설명하면서 추가.
//AUTO
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO) //AUTO는 default이기 때문에 strategy를 명시하지 않아도 된다.
private Long id;
...
}
//IDENTITY
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
}
//SEQUENCE
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
...
}
//TABLE
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
...
}
@GeneratedValue에 들어가서 보면 default가 AUTO로 되어있는데 이 경우 각 DB에 적합한 값을 자동으로 넘겨 처리해주게 된다.
DB 의존성 없이 코딩할 수 있다는 장점때문에 AUTO를 사용하는 경우도 있다.
IDENTITY는 MySQL에서 주로 많이 사용하는 전략이며 MySQL에서의 Auto Increment라고 볼 수 있다.
SEQUENCE는 Oracle이나 Postgre, h2에서 사용한다.
SEQUENCE 전략을 사용한다면 @SequenceGenerator 어노테이션이 필요하다.
@Entity
@SequenceGenerator(
name = "USER_SEQ",
sequenceName = "USER_PK_SEQ",
initialValue = 1,
allocationSize = 50
)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_SEQ")
private Long id;
...
}
@SequenceGenerator는 이렇게 사용하고 속성으로는 name, sequenceName, initialValue, allocationSize, catalog, schema가 있다.
name은 식별자 생성기의 이름.
sequenceName은 데이터베이스에 등록할 sequence명.
initialValue는 sequence 초기값.
allocationSize는 sequence 호출시에 증가하는 수이며 기본값은 50이다. 이 크기를 적당히 설정해야 성능저하를 개선할 수 있다.
catalog, schema는 데이터베이스 catalog, schema 이름이다.
그리고 @GeneratedValue에서 generator에 name을 넣어서 사용하게 된다.
TABLE은 DB 종류에 상관없이 아이디값을 관리하는 별도의 테이블을 만들어두고 그 테이블에서 아이디값을 계속 추출해서 사용할 수 있도록 하고 있다.
Sequence랑 유사하며 @TableGenerator 어노테이션이 필요하다.
@TableGenerator는 @SequenceGenerator와 비슷한 속성을 사용한다.
별도의 테이블을 만들어두고 그 테이블에서 아이디값을 추출한다는 것은 Oracle에서 sequence를 만들어 사용하는것처럼 Sequence 테이블을 만들어 아이디값을 관리하고 이 테이블을 조회해 아이디 값을 가져온 뒤에 업데이트해 다음에 사용할 값을 증가시키는 형태로 운영하는 것을 의미한다.
하지만 최적화 되지 않은 테이블에서 키를 생성하기 때문에 성능 이슈가 발생할 수 있다.
@Entity
@TableGenerator(
name = "USER_SEQ",
table = "USER_PK_SEQ",
pkColumnName = "USER_SEQ_NAME",
pkColumnValue = "USER_SEQ_KEY",
valueColumnName = "USER_SEQ_VAL",
initialValue = 0,
allocationSize = 50
)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "USER_SEQ")
private Long id;
...
}
@TaleGenerator 속성을 좀 보자면
name은 식별자 생성기의 이름.
table은 아이디값을 관리하는 테이블명.
pkColumnName은 컬럼명.
pkColumnValue는 키로 사용할 값의 이름.
valueColumnName은 Sequence 값의 컬럼명.
initialValue는 시작값. 이건 DDL 생성시에 사용한다.
allocationSize는 호출시 증가하는 수. 위에서 설명한것과 같이 적절한 크기를 잘 설정해야 한다.
좀 더 이해하기 편하게 표로 정리.
user_pk_seq(테이블명) | |
user_seq_name (pkColumnName) | user_seq_val (valueColumnName) |
user_seq_key (pkColumnValue) | 0 (DDL로 생성시 초기 initialValue) |
2. @Table
@Table 어노테이션은 테이블에 catalog나 schema를 지정해서 사용할 수 있고 name 역시 지정할 수 있다.
name은 일반적으로 Entity 이름에 맞는 Table name을 자동으로 지정해주기 때문에 따로 사용할 일은 없지만 특별한 경우에 name이나 schema, catalog를 지정할 일이 생긴다.
@Entity
@Table(name = "user_legacy")
public class User {
@Id
@GeneratedValue
private Long id;
...
}
일반적으로 Entity와 동일한 테이블이 DB에 생성되게 되는데 위 처럼 @Table 어노테이션을 통해 name을 설정하게 되면 user 테이블 대신 user_legacy 테이블이 생성된다.
DB 마이그레이션을 하거나 legacy DB에 대해 적용해야 하는 경우 사용할만한 경우고 일반적으로는 Entity 명과 테이블명이 동일한것이 제일 좋은 방식이다.
그리고 @Table 어노테이션에서는 unique Constraints와 indexes를 사용할 수 있다.
@Entity
@Table(name = "user",
indexes = { @Index(ColumnList = "name") },
uniqueConstraints = { @UniqueConstraint(columnNames = {"email"}) }
)
public class User {
@Id
@GeneratedValue
private Long id;
...
}
이런식으로 사용하게 되는데 그럼 로그를 확인해보면 create index .... on user(name) 과
alter table user add constraint ... unique (email) 이런 로그를 확인할 수 있다.
로그를 봤을때 indexes 속성의 경우는 해당 엔티티의 index를 만들어주는데 columnList의 컬럼으로 인덱스를 생성한다는 것을 할 수 있다.
그리고 uniqueConstraints 속성으로 columnNames의 컬럼에 unique 제약조건을 걸어주게 된다.
좀 더 추가적인 속성들을 보자면 indexes의 경우는 index 인터페이스에서 확인할 수 있으며 name, columnList, unique라는 세가지 속성이 있는 것을 볼 수 있다.
name은 생성하고자 하는 index 명이다.
unique의 경우 타입이 boolean으로 되어있는것을 볼 수 있고 default는 false로 되어있다.
unique index를 생성할것인가에 대한 전략인데 기본이 false이기 때문에 따로 설정하지 않는다면
일반적인 index, unique = true로 설정한다면 unique index가 생성된다.
그리고 columnList는 지정할 컬럼이 꼭 있어야 하기 때문에 필수로 넣어야 한다.
uniqueConstarint도 name 속성이 존재하며 제약조건명을 적어주면 된다.
@Entity
@Table(name = "user",
indexes = { @Index(ColumnList = "name", name = "user_index", unique = true) },
uniqueConstraints = { @UniqueConstraint(columnNames = {"email", "name"}, name = "user_unique_constraint") }
)
public class User {
@Id
@GeneratedValue
private Long id;
...
}
이렇게 사용한다.
여기서 주의해야할 점은 이 index나 constriant는 실제 DB에 적용되어있는것과 다를 수 있다는 점이다.
JPAEntity를 활용해 DB DDL을 생성하는 경우에는 어노테이션에 명시한 속성대로 적용이 되지만 일반적으로 많이 사용되는 CRUD 쿼리에 대해서는 아무런 영향을 주지 못한다.
즉, 실제 DB에 Index가 적용되어 있지 않은 상태인데 JPA에 index가 적용되어 있다고 해서 index를 활용한 쿼리가 동작하거나 하는 것은 아니라는 것이다.
호불호가 있는 편이지만 보편적으로는 index나 contraint들은 DB에 맡기고 JPA에서는 표기하지 않는 경우가 좀 더 많다고 한다.
Reference
- 패스트캠퍼스 java/spring 초격차 패키지 Spring Data JPA
- @GenerationValue
@GeneratedValue 전략
직접 기본키를 생성하는 방법 @Id 어노테이션 만을 사용하여 기본키를 직접 할당해주는 방법이 있다. 기본키를 자동으로 생성하는 방법 4가지 > 기본키를 자동으로 생성할 때에는 @Id와 @GenerratedVa
velog.io
JPA - 식별자(@Id) 값 자동 생성
데이터베이스가 관리하는 테이블의 로(ROW)는 기본키(Primary Key)에 의해 식별되고, JPA가 관리하는 엔티티 객체는 @Id로 지정한 식별자 변수를 통해 식별됩니다. JPA는 테이블의 기본 키와 엔티티 식
kdg-is.tistory.com
'Spring' 카테고리의 다른 글
JPA Entity Listener 1 (0) | 2022.03.16 |
---|---|
Jpa Entity 기본 Annotation 2 (@Column, @Transient) (0) | 2022.03.15 |
JPA Enum 적용 (0) | 2022.02.19 |
JPA QueryMethod 2 (where 절 조건 추가) (0) | 2022.02.17 |
JPA QueryMethod 1 (기본 키워드) (0) | 2022.02.14 |