해당 글에서는 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, … | 데이터베이스 필드값을 엔티티 필드값으로 변환 |
javax.persistence (Java(TM) EE 7 Specification APIs)
Interface Summary Interface Description AttributeConverter A class that implements this interface can be used to convert entity attribute state into database column representation and back again. AttributeNode Represents an attribute node of an entity gr
docs.oracle.com
[ 더 알아보기 ]
💡 필드(Field)
- 클래스 내에서 선언된 변수를 의미합니다. 이 변수는 객체의 상태를 저장하며 필드의 값은 객체의 상태를 결정합니다.
3) 엔티티 어노테이션/속성 : 테이블 레벨
💡 엔티티 어노테이션/속성 : 테이블 레벨
- 데이터베이스와 매핑되는 클래스에서 테이블과 관련되어 사용되는 어노테이션과 속성에 대해 알아봅니다.
1. @Entity
💡 @Entity
- 클래스 위에 선언하며 JPA가 관리하는 엔티티임을 나타내는 어노테이션입니다.
- 해당 어노테이션을 생략하면 JPA에서는 해당 클래스를 엔티티로 관리하지 않고 데이터베이스 연산이 수행되지 않습니다.
속성 | 속성 타입 | 필수여부 | default | 설명 |
name | String | 선택 | “” | - 엔티티의 이름을 지정합니다. 이는 JPQL(Java Persistence Query Language)에서 사용되며, 명시적으로 이름을 지정하지 않으면 클래스 이름이 기본값으로 사용됩니다. |
Entity (Java(TM) EE 7 Specification APIs)
name public abstract String name (Optional) The entity name. Defaults to the unqualified name of the entity class. This name is used to refer to the entity in queries. The name must not be a reserved literal in the Java Persistence query language. Defaul
docs.oracle.com
@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 (Java(TM) EE 7 Specification APIs)
Specifies the primary table for the annotated entity. Additional tables may be specified using SecondaryTable or SecondaryTables annotation. If no Table annotation is specified for an entity class, the default values apply. Example: @Entity @Table(name="CU
docs.oracle.com
[더 알아보기]
💡 @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 {
}
Index (Java(TM) EE 7 Specification APIs)
Used in schema generation to specify creation of an index. Note that it is not necessary to specify an index for a primary key, as the primary key index will be created automatically. The syntax of the columnList element is a column_list, as follows: colum
docs.oracle.com
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 | 선택 | “” | 컬럼을 매핑할 테이블 이름 |
Column (Java(TM) EE 7 Specification APIs)
(Optional) The SQL fragment that is used when generating the DDL for the column. Defaults to the generated SQL to create a column of the inferred type.
docs.oracle.com
@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 전략이 있습니다. |
GeneratedValue (Java(TM) EE 7 Specification APIs)
Provides for the specification of generation strategies for the values of primary keys. The GeneratedValue annotation may be applied to a primary key property or field of an entity or mapped superclass in conjunction with the Id annotation. The use of the
docs.oracle.com
💡 GenerationType 클래스의 속성 값
GenerationType 속성 값 | 설명 | 사용 상황 |
GenerationType.AUTO | 특정 DB에 맞게 자동으로 생성 전략을 선택합니다. | DB 종류에 구애받지 않고, 플랫폼에 따라 자동으로 최적의 전략을 선택하려 할 때 |
GenerationType.IDENTITY | DB의 identity 컬럼을 이용해 기본 키를 할당합니다. | 자동으로 증가하는 정수 값을 이용하는 경우 사용함. |
GenerationType.SEQUENCE | DB의 시퀀스를 이용해 기본 키를 할당합니다. | DB에서 제공하는 시퀀스 기능을 이용해 고유한 값을 생성하려 할 때 사용함 |
GenerationType.TABLE | 키 생성 테이블을 이용해 기본 키를 할당합니다. | 특정 테이블을 키 생성 용도로 활용하려 할 때 사용함 |
GenerationType (Java(TM) EE 7 Specification APIs)
AUTO public static final GenerationType AUTO Indicates that the persistence provider should pick an appropriate strategy for the particular database. The AUTO generation strategy may expect a database resource to exist, or it may attempt to create one. A
docs.oracle.com
@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;
}
Lob (Java(TM) EE 7 Specification APIs)
Specifies that a persistent property or field should be persisted as a large object to a database-supported large object type. Portable applications should use the Lob annotation when mapping to a database Lob type. The Lob annotation may be used in conjun
docs.oracle.com
5. @Temporal
💡 @Temporal
- 데이터베이스 날짜 타입과 매핑되는 어노테이션입니다.
속성 | 속성 타입 | 설명 |
value | TemporalType | 매핑할 날짜 타입을 지정합니다. |
💡 TemporalType 속성 값
TemporalType.DATE | 날짜만 저장합니다 (년, 월, 일) |
TemporalType.TIME | 시간만 저장합니다 (시, 분, 초) |
TemporalType.TIMESTAMP | 날짜와 시간을 모두 저장합니다 (년, 월, 일, 시, 분, 초) |
Temporal (Java(TM) EE 7 Specification APIs)
This annotation must be specified for persistent fields or properties of type java.util.Date and java.util.Calendar. It may only be specified for fields or properties of these types. The Temporal annotation may be used in conjunction with the Basic annotat
docs.oracle.com
@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 | 시간대 정보를 포함한 날짜와 시간을 나타내는 클래스 |
UpdateTimestamp (Hibernate JavaDocs)
docs.jboss.org
8. @Embeddable
💡 @Embeddable
- 클래스가 값 타입을 구현하고 있음을 지정하는 데 사용하는 어노테이션입니다. 이를 사용하면 여러 엔티티에서 재사용 가능한 공통 클래스를 정의할 수 있습니다.
- @Embeddable 어노테이션을 사용하려면, 해당 클래스는 Serializable 인터페이스를 구현해야 합니다. 또한, 이 클래스는 기본 생성자를 포함해야 하고, 이 생성자는 public 또는 protected여야 합니다.
- 해당 어노테이션은 속성이 존재하지 않습니다.
Embeddable (Java(TM) EE 7 Specification APIs)
Specifies a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity. Each of the persistent properties or fields of the embedded object is mapped to the database table for the entity. Note that the Tra
docs.oracle.com
💡 @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;
}
EmbeddedId (Java(TM) EE 7 Specification APIs)
Applied to a persistent field or property of an entity class or mapped superclass to denote a composite primary key that is an embeddable class. The embeddable class must be annotated as Embeddable. There must be only one EmbeddedId annotation and no Id an
docs.oracle.com
[ 더 알아보기 ]
💡@Embeddable 어노테이션의 경우 클래스 밖에서 선언을 해야 하는 건가?
- 일반적으로 클래스 내부에 포함되어 있지 않으며, 별도의 클래스로 선언됩니다.
- 이 클래스는 필드 그룹을 재사용할 수 있게 해주는 엔티티에 포함됩니다. 따라서, Embeddable 클래스는 일반적으로 엔티티 클래스 외부에서 선언됩니다.
💡 [참고] 복합 키(Composite Key)
- ‘두 개 이상의 열을 조합’하여 ‘고유한 값’을 나타내는 키를 의미합니다.
- 이러한 키는 하나의 열만으로 유일성을 보장할 수 없는 경우 사용이 됩니다. 대표적으로 주문서 번호와 주문 내역 상세번호를 합쳐서 고유한 값을 나타내는 경우가 있습니다.

💡 [참고] 관계형 데이터베이스의 키에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
[DB] 관계형 데이터베이스 키(Key) 이해하기
해당 글에서는 관계형 데이터 베이스의 키에 대해 이해하고 각각의 종류들에 대해 이해를 돕기 위해 작성한 글입니다. 1) 데이터베이스 키(Key) 💡 데이터베이스 키(Key) - 데이터베이스에서 각 ‘
adjh54.tistory.com
10. @Embedded
💡 @Embedded
- 엔티티 내에서 다른 객체를 임베디드 하는 데 사용하는 어노테이션입니다.
- 이를 통해 객체지향적인 설계를 유지하면서 데이터베이스 테이블을 객체에 매핑할 수 있습니다. 해당 어노테이션의 속성은 존재하지 않습니다.
Embedded (Java(TM) EE 7 Specification APIs)
Specifies a persistent field or property of an entity whose value is an instance of an embeddable class. The embeddable class must be annotated as Embeddable. The AttributeOverride, AttributeOverrides, AssociationOverride, and AssociationOverrides annotati
docs.oracle.com
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의 ‘이름’을 데이터베이스에 저장합니다. |
Enumerated (Java(TM) EE 7 Specification APIs)
docs.oracle.com
💡 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에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
[Java] Enum(Enumerated type) : 열거형 이해하기 -1 : 정의, 주요특징, 메서드, 활용 예시
해당 글에서는 Java에서 Enum에 대해 이해하고 이를 활용할 수 있는 방안에 대해서 알아봅니다. 1) Enum(Enumerated type) : 열거형 💡 Enum(Enumerated type) : 열거형 - 특정 값들의 집합을 나타내는 데이터 타
adjh54.tistory.com
12. @Transient
💡 @Transient
- 데이터베이스와 매핑되지 않는 어노테이션입니다.
- 즉 해당 어노테이션이 붙은 필드는 데이터베이스와 매핑되지 않습니다. 일시적인 데이터를 저장하거나 데이터베이스에 저장할 필요가 없는 정보를 담을 때 사용합니다.
- 해당 어노테이션의 속성은 존재하지 않습니다.
@Table(name = "tb_user")
public class UserEntity implements Serializable {
@Transient
private String temporaryData;
}
Transient (Java(TM) EE 7 Specification APIs)
docs.oracle.com
13. @Convert
💡 @Convert
- 데이터베이스 필드값을 엔티티 필드값으로 변환하는 데 사용하는 어노테이션입니다.
속성 | 타입 | 설명 |
attributeName | String | 변환을 적용할 속성의 이름을 지정 |
converter | Class | 변환기를 지정 |
disableConversion | boolean | 변환을 비활성화 할지 여부를 지정 |
Convert (Java(TM) EE 7 Specification APIs)
Specifies the conversion of a Basic field or property. It is not necessary to use the Basic annotation or corresponding XML element to specify the Basic type. The Convert annotation should not be used to specify conversion of the following: Id attributes,
docs.oracle.com
💡 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;
}
}
}
오늘도 감사합니다. 😀