반응형
해당 글에서는 Spring Boot Data JPA에서 엔티티의 어노테이션과 어노테이션 속성에 대해 이해를 돕기 위해 작성한 글입니다.
💡 [참고] JPA 관련해서 구성 내용에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
분류 | 링크 |
Spring Boot Data JPA -1: ORM, JPA, Hibernate, QueryDSL 이론 | https://adjh54.tistory.com/421 |
Spring Boot Data JPA -2: 초기 환경 구성 + JpaRepository 활용 방법 | https://adjh54.tistory.com/422 |
Spring Boot Data JPA -3: 상세 JpaRepository 활용 방법 | https://adjh54.tistory.com/481 |
Spring Boot Data JPA 엔티티 어노테이션 -1 : 테이블 컬럼 단위 | https://adjh54.tistory.com/466 |
Spring Boot Data JPA 엔티티 어노테이션 -2 : 엔티티(테이블)간의 관계 | https://adjh54.tistory.com/477 |
Spring Boot Data JPA FetchType 이해하기 : 즉시/지연로딩 | https://adjh54.tistory.com/476 |
Spring Boot Data JPA + JPQL 활용 방법 | https://adjh54.tistory.com/479 |
Spring Boot Data JPA + Criteria API 활용 방법 | https://adjh54.tistory.com/483 |
Spring Boot Data JPA + QueryDSL 활용 방법-1 : 정의 및 구성요소 | https://adjh54.tistory.com/484 |
Spring Boot Data JPA + QueryDSL 활용 방법-2 : 초기 환경설정 및 활용예시 | https://adjh54.tistory.com/485 |
1) JPA 엔티티(Entity)
💡 JPA 엔티티(Entity)
- 데이터베이스의 테이블을 자바 클래스로 매핑하는 것을 의미합니다. 이 엔티티 클래스는 데이터베이스 테이블의 각 행을 표현하며, 클래스의 인스턴스는 특정 테이블의 한 행에 해당합니다.
- 데이터베이스 연산을 추상화하며 이를 통해 개발자는 SQL 쿼리에 의존하지 않고 데이터베이스와 상호작용할 수 있습니다. 이는 객체 지향 프로그래밍과 데이터베이스 간의 패러다임 불일치를 해결하는데 도움이 됩니다.
2) Entity 주요 어노테이션
1. 요약
Annotation | 제공 패키지 | 분류 | DB 매핑 정보 | 설명 |
@Entity | javax.persistence | 테이블 단위 | 클래스를 엔티티 클래스로 지정 | |
@Table | javax.persistence | 테이블 단위 | Table | 클래스를 매핑할 테이블로 지정 |
@Access | javax.persistence | 테이블 단위/컬럼 단위 | 데이터베이스 접근 방식을 지정 | |
@Index | javax.persistence | 테이블 단위/컬럼 단위 | Table Index | 데이터베이스의 인덱스를 지정 |
@Column | javax.persistence | 컬럼 단위 | Colmn(VARCHAR, INT..) | 클래스의 필드를 테이블의 컬럼으로 지정 |
@Id | javax.persistence | 컬럼 단위 | Primary Key | 클래스의 필드를 기본 키(Primary Key)로 지정 |
@GeneratedValue | javax.persistence | 컬럼 단위 | Primary Key 전략 | 기본 키(Primary Key) 생성 전략을 지정 |
@Lob | javax.persistence | 컬럼 단위 | CLOB, BLOB | 클래스의 필드를 대용량 데이터(CLOB, BLOB)을 지정 |
@Temporal | javax.persistence | 컬럼 단위 | Date, Time, Timstamp | 클래스의 필드를 날짜 타입을 지정 |
@CreationTimestamp | org.hibernate.annotations | 컬럼 단위 | Date, Calendar, … | 엔티티 생성시 타임스탬프를 저장 |
@UpdateTimestamp | org.hibernate.annotations | 컬럼 단위 | Date, Calendar, … | 엔티티 수정시 타임스탬프를 저장 |
@Embeddable | javax.persistence | 컬럼 단위 | 임베디드 타입을 구성 | |
@EmbeddedId | javax.persistence | 컬럼 단위 | 복합키 | 임베디드 타입을 참조하여 컬럼으로 복합키 지정 |
@Embedded | javax.persistence | 컬럼 단위 | 임베디드 타입을 참조하여 임베디드 타입 지정 | |
@Enumerated | javax.persistence | 컬럼 단위 | 값이 정의된 VARCHAR, INT… | 클래스의 필드를 자바 Enum 타입을 매핑 |
@Transient | javax.persistence | 컬럼 단위 | 컬럼 매핑 제외 | 클래스의 필드를 테이블의 컬럼과의 매핑을 지정하지 않음 |
@Convert | javax.persistence | 컬럼 단위 | JSON, JSONB, … | 데이터베이스 필드값을 엔티티 필드값으로 변환 |
[ 더 알아보기 ]
💡 필드(Field)
- 클래스 내에서 선언된 변수를 의미합니다. 이 변수는 객체의 상태를 저장하며 필드의 값은 객체의 상태를 결정합니다.
3) 엔티티 어노테이션/속성 : 테이블 레벨
💡 엔티티 어노테이션/속성 : 테이블 레벨
- 데이터베이스와 매핑되는 클래스에서 테이블과 관련되어 사용되는 어노테이션과 속성에 대해 알아봅니다.
1. @Entity
💡 @Entity
- 클래스 위에 선언하며 JPA가 관리하는 엔티티임을 나타내는 어노테이션입니다.
- 해당 어노테이션을 생략하면 JPA에서는 해당 클래스를 엔티티로 관리하지 않고 데이터베이스 연산이 수행되지 않습니다.
속성 | 속성 타입 | 필수여부 | default | 설명 |
name | String | 선택 | “” | - 엔티티의 이름을 지정합니다. 이는 JPQL(Java Persistence Query Language)에서 사용되며, 명시적으로 이름을 지정하지 않으면 클래스 이름이 기본값으로 사용됩니다. |
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "user_sq", unique = true)
private long userSq;
}
2. @Table
💡 @Table
- 실제 데이터베이스에 존재하는 테이블 이름을 매핑하는 어노테이션입니다.
- 해당 어노테이션의 name 속성을 통해 지정하여 엔티티와 테이블이 매핑이 됩니다.
속성 | 속성 타입 | 필수여부 | default | 설명 |
name | String | 선택 | “” | 매핑할 테이블의 이름을 지정 |
catalog | String | 선택 | “” | 데이터베이스의 카탈로그를 지정 |
indexes | Index[] | 선택 | “” | 테이블의 인덱스를 지정 |
schema | String | 선택 | “” | 테이블이 있는 스키마를 지정 |
uniqueConstraints | UniqueConstraint[] | 선택 | {} | 테이블의 고유 제약 조건을 지정 |
[더 알아보기]
💡 @Table 어노테이션에 name 속성을 명시하지 않으면 어떻게 될까?
- 기본적으로 클래스 이름이 테이블 이름으로 매핑이 됩니다.
- 따라서 특별히 name을 지정하지 않아도 자동으로 클래스 이름과 동일한 테이블을 찾아 매핑이 이루어집니다.
- tb_user라는 테이블이라면 TbUser라는 이름의 클래스명으로 지정을 하면 됩니다.
// Normal
@Entity
@Table(name = "TB_USER")
public class User {
}
// Optionanl Add
@Entity
@Table(
name = "TB_USER",
schema = "public",
indexes = {@Index(name = "index_user_name", columnList = "name")},
uniqueConstraints = @UniqueConstraint(columnNames = {"username"})
)
public class User {
}
3. @Access
💡 @Access
- JPA가 데이터에 접근하는 방식을 결정하는 어노테이션으로 어떻게 데이터를 읽고 쓰는지, 즉 데이터의 저장과 조회를 어떻게 처리하는 방식을 지정합니다.
- 두 가지 접근 방식으로 FIELD와 PROPERTY를 제공합니다.
접근 방식 | 설명 |
@Access(AccessType.FIELD) | 인스턴스 변수에 직접 접근하여 데이터를 처리하는 방식 |
@Access(AccessType.PROPERTY) | getter와 setter를 사용하여 데이터를 처리하는 방식 |
💡 @Access(AccessType.FIELD)를 이용한 접근 방식
- 엔티티 클래스 내에 @Id, @Column 어노테이션으로 지정하여 인스턴스 변수에 직접 접근하여 데이터를 처리하는 방식으로 사용이 됩니다.
@Entity
@Access(AccessType.FIELD)
public class Member {
@Id
private String id;
@Column
private String userName;
}
💡 @Access(AccessType.PROPERTY)를 이용한 접근 방식
- 엔티티 내에 @Trasient을 통해 데이터베이스 컬럼과 매핑을 하지 않는 firstName, lastName 필드가 존재합니다.
- fullName 필드에서는 firstName과 lastName을 결합한 값을 가집니다. 이 결합은 @Access(AccessType.PROPERTY) 접근 방식으로 프로퍼티 접근 방식을 이용하여 접근을 하며 최종적으로 getFullName() 메서드를 통해 fullName의 값을 가져오는 것을 의미합니다.
@Entity
public class Member {
@Id
private String id;
@Trasient
private Stirng firstName;
@Trasient
private Stirng lastName;
private String fullName;
@Access(AccessType.PROPERTY)
public String getFullName() {
return firstName + lastName;
}
}
[더 알아보기 ]
💡 @Access(AccessType.FIELD), @Access(AccessType.PROPERTY) 접근방식을 사용하지 않으면 어떻게 될까?
- @Access 어노테이션을 명시적으로 사용하지 않을 경우, 디폴트 접근 전략은 JPA 구현체가 결정합니다.
- 엔티티 클래스 내에서 @Id 어노테이션이 붙은 필드 또는 프로퍼티를 찾고 @Id가 붙은 곳이 필드에 있으면 FIELD 접근 전략을, 프로퍼티에 있으면 PROPERTY 접근 전략을 사용합니다.
4. @Index
💡 @Index
- 테이블 테이블의 인덱스를 정의하는 데 사용되는 어노테이션입니다.
- 해당 어노테이션이 적용된 필드는 검색 성능을 향상하기 위해 데이터베이스에서 별도로 인덱싱 됩니다.
- 인덱스 이름, 인덱싱할 컬럼명, 인덱스 유니크 여부 속성을 지정할 수 있습니다.
속성 | 속성 타입 | 필수여부 | default | 설명 |
columnList | String | 필수 | “” | 인덱스를 생성할 컬럼의 이름을 쉼표(,)로 구분하여 지정합니다. |
name | String | 선택 | “” | 인덱스의 이름을 지정합니다. |
unique | boolean | 선택 | false | 중복 허용여부를 지정합니다. |
@Table(name = "USER", indexes = {@Index(name = "index_user_name", columnList = "name")})
public class UserEntity implements Serializable {
}
4) 엔티티 어노테이션/속성: 컬럼 레벨(필드)
💡 엔티티 어노테이션/속성 : 컬럼 레벨(필드)
- 데이터베이스와 매핑되는 클래스에서 테이블의 컬럼과 관련되어 사용되는 어노테이션과 속성에 대해 알아봅니다.
1. @Column
💡 @Column
- 필드를 데이터베이스 컬럼에 매핑하는 어노테이션입니다.
속성 | 속성 타입 | 필수여부 | default | 설명 |
name | String | 선택 | “” | 매핑할 데이터베이스 컬럼 이름 |
columnDefinition | String | 선택 | “” | 컬럼의 타입, 길이, 제약조건 등을 직접 지정 |
unique | boolean | 선택 | false | 중복 허용 여부를 결정 |
length | int | 선택 | 255 | 문자열의 길이를 설정 |
nullable | boolean | 선택 | true | null 허용 여부를 결정 (default: true) |
insertable | boolean | 선택 | true | 등록시에 매핑 여부를 결정 (default: true) |
updatable | boolean | 선택 | true | 수정 시에 매핑 여부를 결정 (default: true) |
precision | int | 선택 | 0 | BigDecimal 타입에서 사용, 소수점 포함 숫자의 총 자릿수 |
scale | int | 선택 | 0 | BigDecimal 타입에서 사용, 소수점 이하 자릿수 |
table | String | 선택 | “” | 컬럼을 매핑할 테이블 이름 |
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Column(name = "name")
private String name;
@Column(
name = "example_column",
columnDefinition = "VARCHAR(255) DEFAULT 'unknown'",
insertable = true,
length = 255,
nullable = false,
precision = 10,
scale = 2,
table = "example_table",
unique = false,
updatable = true
)
private String exampleField;
}
[ 더 알아보기 ]
💡 @Column 어노테이션의 name을 지정하지 않으면 어떻게 매핑이 될까?
- @Column 어노테이션은 필드 이름이 기본적으로 컬럼 이름으로 매핑됩니다.
- 따라서 특별히 이름을 지정하지 않아도 자동으로 필드 이름과 동일한 컬럼을 찾아 매핑이 이루어집니다.
- 예시로 userAddr라는 필드 이름으로 지정하면 user_addr라는 DB 컬럼에 자동으로 매핑됩니다.
2. @Id
💡 @Id
- 엔티티 내에서 기본 키(Primary Key) 필드를 지정하는 데 사용하는 어노테이션입니다.
- 해당 어노테이션의 속성은 존재하지 않습니다.
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Id
private long userSq;
}
3. @GeneratedValue
💡 @GeneratedValue
- 엔티티의 기본 키(Primary Key)를 자동으로 생성하기 위해 사용되는 어노테이션입니다.
- 이는 직접 개발자가 키를 관리하는 것이 아니라 JPA가 알아서 키 값을 생성하고 관리합니다.
- 다양한 자동 키 생성에 대한 사용이 가능합니다.
속성 | 속성 타입 | 필수 여부 | default | 설명 |
generator | String | 선택 | “” | 기본 키 생성에 사용할 생성기의 이름을 지정합니다. |
strategy | GenerationType | 선택 | GenerationType.AUTO | 기본 키의 생성 전략을 지정합니다. AUTO, IDENTITY, SEQUENCE, TABLE 전략이 있습니다. |
💡 GenerationType 클래스의 속성 값
GenerationType 속성 값 | 설명 | 사용 상황 |
GenerationType.AUTO | 특정 DB에 맞게 자동으로 생성 전략을 선택합니다. | DB 종류에 구애받지 않고, 플랫폼에 따라 자동으로 최적의 전략을 선택하려 할 때 |
GenerationType.IDENTITY | DB의 identity 컬럼을 이용해 기본 키를 할당합니다. | 자동으로 증가하는 정수 값을 이용하는 경우 사용함. |
GenerationType.SEQUENCE | DB의 시퀀스를 이용해 기본 키를 할당합니다. | DB에서 제공하는 시퀀스 기능을 이용해 고유한 값을 생성하려 할 때 사용함 |
GenerationType.TABLE | 키 생성 테이블을 이용해 기본 키를 할당합니다. | 특정 테이블을 키 생성 용도로 활용하려 할 때 사용함 |
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long userSq;
}
[ 더 알아보기 ]
💡 MySQL의 ‘AUTO_INCREMENT’나 PostgreSQL의 ‘serial’을 통해 정수가 자동으로 올라가는 형태를 구현하려면 어떤 전략을 사용해야 할까?
- GenerationType.IDENTITY 전략을 사용해야 합니다.
4. @Lob
💡 @Lob
- 대용량 데이터인 CLOB, BLOB 데이터와 매핑에 사용하는 어노테이션입니다.
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Lob
private String content;
}
5. @Temporal
💡 @Temporal
- 데이터베이스 날짜 타입과 매핑되는 어노테이션입니다.
속성 | 속성 타입 | 설명 |
value | TemporalType | 매핑할 날짜 타입을 지정합니다. |
💡 TemporalType 속성 값
TemporalType.DATE | 날짜만 저장합니다 (년, 월, 일) |
TemporalType.TIME | 시간만 저장합니다 (시, 분, 초) |
TemporalType.TIMESTAMP | 날짜와 시간을 모두 저장합니다 (년, 월, 일, 시, 분, 초) |
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Temporal(TemporalType.DATE)
private Date date;
}
6. @CreationTimestamp
💡 @CreationTimestamp
- Hibernate에서 제공해 주는 어노테이션으로 데이터베이스 내에 INSERT 작업이 수행이 되면 지정한 컬럼에 컬럼 타입이 매핑되어 자동으로 값이 저장될 수 있도록 하는 어노테이션입니다.
- 예를 들면, @CreationTimeStamp를 변수에 선언하고, LocalDateTime로 타입을 지정하면 해당 테이블의 INSERT 작업이 발생하면 ‘시간을 나타내는 클래스 (날짜는 포함하지 않음)’ 형태로 값이 자동 저장 됩니다.
- 해당 어노테이션의 속성은 존재하지 않습니다.
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@CreationTimestamp
private LocalDateTime createdDate;
}
💡 @CreationTimestamp 어노테이션에서 사용 가능타입
클래스 | 설명 |
Date | 날짜와 시간을 나타내는 클래스 |
Calendar | 날짜와 시간을 계산하는 클래스 |
Time | 시간을 나타내는 클래스 |
Timestamp | 특정 시간을 나타내는 클래스 |
Instant | 시간을 초단위로 나타내는 클래스 |
LocalDate | 날짜를 나타내는 클래스 (시간은 포함하지 않음) |
LocalDateTime | 날짜와 시간을 나타내는 클래스 |
LocalTime | 시간을 나타내는 클래스 (날짜는 포함하지 않음) |
MonthDay | 월과 일을 나타내는 클래스 |
OffsetDateTime | 시간대 오프셋(UTC와의 차이)을 포함한 날짜와 시간을 나타내는 클래스 |
OffsetTime | 시간대 오프셋을 포함한 시간을 나타내는 클래스 |
Year | 연도를 나타내는 클래스 |
YearMonth | 연도와 월을 나타내는 클래스 |
ZonedDateTime | 시간대 정보를 포함한 날짜와 시간을 나타내는 클래스 |
7. @UpdateTimestamp
💡 @UpdateTimestamp
- Hibernate에서 제공해 주는 어노테이션으로 데이터베이스 내에 UPDATE 작업이 수행이 되면 지정한 컬럼에 컬럼 타입이 매핑되어 자동으로 값이 저장될 수 있도록 하는 어노테이션입니다.
- 예를 들면, @CreationTimeStamp를 변수에 선언하고, LocalDateTime로 타입을 지정하면 해당 테이블의 UPDATE 작업이 발생하면 ‘시간을 나타내는 클래스 (날짜는 포함하지 않음)’ 형태로 값이 자동 저장 됩니다. 해당 어노테이션의 속성은 존재하지 않습니다.
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@UpdateTimestamp
private LocalDateTime updatedDate;
}
💡 @UpdateTimestamp 어노테이션에서 사용 가능타입
클래스 | 설명 |
Date | 날짜와 시간을 나타내는 클래스 |
Calendar | 날짜와 시간을 계산하는 클래스 |
Time | 시간을 나타내는 클래스 |
Timestamp | 특정 시간을 나타내는 클래스 |
Instant | 시간을 초단위로 나타내는 클래스 |
LocalDate | 날짜를 나타내는 클래스 (시간은 포함하지 않음) |
LocalDateTime | 날짜와 시간을 나타내는 클래스 |
LocalTime | 시간을 나타내는 클래스 (날짜는 포함하지 않음) |
MonthDay | 월과 일을 나타내는 클래스 |
OffsetDateTime | 시간대 오프셋(UTC와의 차이)을 포함한 날짜와 시간을 나타내는 클래스 |
OffsetTime | 시간대 오프셋을 포함한 시간을 나타내는 클래스 |
Year | 연도를 나타내는 클래스 |
YearMonth | 연도와 월을 나타내는 클래스 |
ZonedDateTime | 시간대 정보를 포함한 날짜와 시간을 나타내는 클래스 |
8. @Embeddable
💡 @Embeddable
- 클래스가 값 타입을 구현하고 있음을 지정하는 데 사용하는 어노테이션입니다. 이를 사용하면 여러 엔티티에서 재사용 가능한 공통 클래스를 정의할 수 있습니다.
- @Embeddable 어노테이션을 사용하려면, 해당 클래스는 Serializable 인터페이스를 구현해야 합니다. 또한, 이 클래스는 기본 생성자를 포함해야 하고, 이 생성자는 public 또는 protected여야 합니다.
- 해당 어노테이션은 속성이 존재하지 않습니다.
💡 @Embeddable 선언부
- Address라는 객체를 구현한 클래스입니다.
package com.adjh.multiflex.jpa.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Embeddable;
import java.io.Serializable;
@Getter
@Setter
@Embeddable
public class Address implements Serializable {
private String street;
private String city;
private String state;
private String zip;
protected Address() {
}
public Address(String street, String city, String state, String zip) {
this.street = street;
this.city = city;
this.state = state;
this.zip = zip;
}
}
💡 @Embedded를 이용한 참조부
- Address로 임베디드 타입을 지정하기 위해 사용합니다.
@Entity
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long userSq;
@Embedded
private Address address;
}
9. @EmbeddedId
💡 @EmbeddedId
- 복합키를 지정하는 데 사용하는 어노테이션입니다.
- 해당 어노테이션의 속성은 존재하지 않습니다.
💡 @Embeddable 선언부
- 복합키를 구성할 수 있도록 EmployeeId 클래스 내에 구현합니다.
@Getter
@Setter
@Embeddable
public class EmployeeId implements Serializable {
private String companyId;
private String employeeId;
}
@Embeddable
public class EmployeeId implements Serializable {
private String companyId;
private String employeeId;
}
@Entity
public class Employee {
@EmbeddedId
private EmployeeId id;
private String name;
}
[ 더 알아보기 ]
💡@Embeddable 어노테이션의 경우 클래스 밖에서 선언을 해야 하는 건가?
- 일반적으로 클래스 내부에 포함되어 있지 않으며, 별도의 클래스로 선언됩니다.
- 이 클래스는 필드 그룹을 재사용할 수 있게 해주는 엔티티에 포함됩니다. 따라서, Embeddable 클래스는 일반적으로 엔티티 클래스 외부에서 선언됩니다.
💡 [참고] 복합 키(Composite Key)
- ‘두 개 이상의 열을 조합’하여 ‘고유한 값’을 나타내는 키를 의미합니다.
- 이러한 키는 하나의 열만으로 유일성을 보장할 수 없는 경우 사용이 됩니다. 대표적으로 주문서 번호와 주문 내역 상세번호를 합쳐서 고유한 값을 나타내는 경우가 있습니다.
💡 [참고] 관계형 데이터베이스의 키에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
10. @Embedded
💡 @Embedded
- 엔티티 내에서 다른 객체를 임베디드 하는 데 사용하는 어노테이션입니다.
- 이를 통해 객체지향적인 설계를 유지하면서 데이터베이스 테이블을 객체에 매핑할 수 있습니다. 해당 어노테이션의 속성은 존재하지 않습니다.
package com.adjh.multiflex.jpa.entity;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Embeddable;
import java.io.Serializable;
@Getter
@Setter
@Embeddable
public class Address implements Serializable {
private String street;
private String city;
private String state;
private String zip;
protected Address() {
}
public Address(String street, String city, String state, String zip) {
this.street = street;
this.city = city;
this.state = state;
this.zip = zip;
}
}
💡 @Embedded를 이용한 참조부
- Address로 임베디드 타입을 지정하기 위해 사용합니다.
@Entity
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long userSq;
@Embedded
private Address address;
}
11. @Enumerated
💡 @Enumerated
- 엔티티 클래스의 필드를 열거 타입(eunm)으로 매핑하기 위해 사용되는 어노테이션입니다.
- 자바의 enum을 데이터베이스의 정수형 또는 문자열형으로 자동 변환하여 저장할 수 있습니다.
- 데이터 타입으로 들어올 수 있는 값이 지정되어 있는 경우 사용할 수 있습니다. 예를 들어서 USER_STATE라는 데이터베이스 컬럼이 있는데, 해당 경우는 활성화(A), 삭제(D), 회원탈퇴(W)의 세 가지 경우를 가지는 경우에 ENUM 타입으로 3가지 값을 정해서 사용이 가능합니다.
속성 | 속성 타입 | 설명 |
value | EnumType | 매핑할 enum 타입을 지정합니다. EnumType.ORDINAL과 EnumType.STRING 중 하나를 선택할 수 있습니다. |
💡 EnumType 클래스의 속성
EnumType | 설명 |
EnumType.ORDINAL | enum의 ‘순서’를 데이터베이스에 저장합니다 |
EnumType.STRING | enum의 ‘이름’을 데이터베이스에 저장합니다. |
💡 UserStateEnum이라는 값으로 ACTIVE: 활성화(A), DELETE: 삭제(D), WITHDRAWAL: 회원탈퇴(W) 값으로 구성했습니다. 해당 부분에서 실제 컬럼의 값으로 들어갈 수 있는것은 'A', 'D', 'W'입니다.
package com.adjh.multiflex.jpa.entity.enums;
import lombok.Getter;
/**
* 사용자의 상태를 관리합니다.
*
* @author : lee
* @fileName : UserStEnum
* @since : 4/8/24
*/
@Getter
public enum UserStEnum {
A("ACTIVE", "활성화"), // 활성화
D("DELETE", "삭제"), // 삭제
W("WITHDRAWAL", "회원탈퇴"); // 회원탈퇴
private final String value;
private final String desc;
UserStEnum(String value, String desc) {
this.value = value;
this.desc = desc;
}
}
💡 tb_user라는 테이블에 userState라는 컬럼 값이 있습니다.
- 해당 값에는 활성화(A), 삭제(D), 회원탈퇴(W) 값만 들어올 수 있다는 가정 하라면 @Enumerated을 통해서 들어오는 값에 대해 지정할 수 있습니다.
@Entity
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long userSq;
// 다른 필드들...
@Enumerated(EnumType.STRING)
private UserStateEnum userState;
}
💡 [참고] enum에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
12. @Transient
💡 @Transient
- 데이터베이스와 매핑되지 않는 어노테이션입니다.
- 즉 해당 어노테이션이 붙은 필드는 데이터베이스와 매핑되지 않습니다. 일시적인 데이터를 저장하거나 데이터베이스에 저장할 필요가 없는 정보를 담을 때 사용합니다.
- 해당 어노테이션의 속성은 존재하지 않습니다.
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Transient
private String temporaryData;
}
13. @Convert
💡 @Convert
- 데이터베이스 필드값을 엔티티 필드값으로 변환하는 데 사용하는 어노테이션입니다.
속성 | 타입 | 설명 |
attributeName | String | 변환을 적용할 속성의 이름을 지정 |
converter | Class | 변환기를 지정 |
disableConversion | boolean | 변환을 비활성화 할지 여부를 지정 |
💡 permissions의 값으로 아래와 같은 형태의 데이터가 들어올 경우 매핑을 하기 위해 사용합니다.
"host": {
"write" : true,
"read": true
},
"guest": {
"wrtie": false,
"read": true
}
💡 @Convert로 JpaJsonConverter 클래스를 참조하고 있습니다.
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Column
@Convert(converter = JpaJsonConverter.class)
private Map<String, JSONObject> permissions = new HashMap<String, JSONObject>();
}
💡 JpaJsonConverter 클래스에서는 String, Object 형태의 데이터가 전달되면 HashMap 형태로 매핑을 하여 데이터를 전달받습니다.
package com.adjh.multiflex.jpa.common;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import javax.persistence.AttributeConverter;
import java.util.HashMap;
import java.util.Map;
/**
* HashMap to JSON String, JSON String to HashMap Converter
*
* @author : lee
* @fileName : JpaJsonConverter
* @since : 4/5/24
*/
@Slf4j
public class JpaJsonConverter implements AttributeConverter<Map<String, Object>, String> {
ObjectMapper objectMapper = new ObjectMapper();
/**
* Map 객체를 JSON 문자열로 변환합니다. (Map to JsonString)
*
* @param paramMap : {Map<String, Object>}
* @return String : resultJsonStr
*/
@Override
public String convertToDatabaseColumn(Map<String, Object> paramMap) {
String resultJsonStr = null;
try {
resultJsonStr = objectMapper.writeValueAsString(paramMap);
} catch (JsonProcessingException e) {
log.error("[-] Convert Map to JSON String Fail :: " + e.getMessage());
}
return resultJsonStr;
}
/**
* JSON 문자열을 Map 객체로 변환합니다.(JsonString to Map)
*
* @param paramStr {String}
* @return {Map<String, Object>}
*/
@Override
public Map<String, Object> convertToEntityAttribute(String paramStr) {
// [CASE1] JSON String 값이 존재하지 않으면 빈 Map 값 반환
if (paramStr == null || paramStr.isEmpty()) {
return new HashMap<String, Object>();
}
// [CASE2] JSON String 값이 존재하면 변환한 값을 반환
else {
Map<String, Object> resultMap = null;
try {
resultMap = objectMapper.readValue(paramStr, HashMap.class);
} catch (JsonProcessingException e) {
log.error("[-] Convert JSON String to Map Fail :: " + e.getMessage());
}
return resultMap;
}
}
}
오늘도 감사합니다. 😀
반응형