매핑 어노테이션(Mapping Annotation)

JOY🌱·2023년 4월 7일
0

🐸 JPA

목록 보기
3/8
post-thumbnail

👀 Entity Mapping

GitHub

👉 @Entity

💁‍♀️ 해당 클래스를 엔티티로 설정하기 위한 어노테이션
프로젝트 내에 다른 패키지에도 동일한 엔티티가 존재하는 경우, 해당 엔티티를 식별하기 위한 중복되지 않는 name을 지정해줘야함

@Entity(name="section01_member")
@Table(name="TBL_MEMBER_SECTION01")
public class Member {}
  • 엔티티 생성 시 유의사항
    • 기본 생성자는 필수로 작성해야함
    • final 클래스, enum, interface, inner class 에서는 사용 불가
    • 저장할 필드에 final을 사용하면 안됨

👉 @Table

💁‍♀️ 매핑 될 테이블의 이름을 작성하기 위한 어노테이션
생략 시, 자동으로 클래스의 이름을 테이블의 이름으로 사용
실제로 존재하지 않는 테이블명 작성 시, 새로 테이블을 생성

@Entity(name="section01_member")
@Table(name="TBL_MEMBER_SECTION01")
public class Member {}

👀 Column Mapping

GitHub

👉 @Column

💁‍♀️ 객체 필드를 테이블의 컬럼에 매핑시켜주는 어노테이션

@Column(name="MEMBER_ID")
private String memberId;

@Column 어노테이션에 사용 가능한 속성들

  • name : 필드와 매핑할 테이블의 컬럼 이름
  • nullable : null값 허용 여부 설정. not null 제약조건에 해당함 (true 기본값)
  • unique : 한 컬럼에 unique 제약조건을 설정 (기본값은 없으며, 두 개 이상 컬럼에 unique 제약조건을 설정하기 위해서는 클래스 레벨에서 @Table의 uniqueConstraints 속성에 설정)
  • columnDefinition : 데이터베이스 컬럼 정보를 직접 기입 (필드의 자바 타입과 방언 정보를 사용해서 적절한 컬럼 타입을 생성)
  • length : 문자 길이 제약조건, String 타입에서만 사용(255 기본값)
  • insertable : 엔티티 저장 시 이 필드도 같이 저장(true 기본값)
  • updatable : 엔티티 수정 시 이 필드도 같이 수정(true 기본값)
  • table : 하나의 엔티티를 두 개 이상의 테이블에 매핑할 때 사용(현재 클래스가 매핑된 테이블)

주로 name과 nullable을 사용하며, insertable과 updateable은 정보를 읽기만 하고 실수로 변경하게 될 것을 미연에 방지하고자 설정
다만 애플리케이션 레벨에서 DDL 구분을 직접 사용하지 않는 것이 더 바람직

//	@Column(name="PHONE", nullable=false)	// not null 조건 추가
//	@Column(name="PHONE", unique=true)		// unique 조건 추가
	@Column(name="PHONE", columnDefinition="varchar2(200) default '010-0000-0000'") // 사이즈는 200, 기본값을 따로 설정 가능
	private String phone;

👉 @Transient

💁‍♀️ 테이블 생성 시 무시되는 컬럼을 표시하기 위한 어노테이션

@Column(name="NICKNAME")
@Transient
private String nickname;

사용 후, 실제 DB에는 'NICKNAME' 컬럼이 생성되지않음

👉 @Temporal

💁‍♀️ 데이터베이스와 Java 객체 간에 일치시키기 위한 날짜 및 시간 형식을 지정하기 위한 어노테이션

@Column(name="ENROLL_DATE")
@Temporal(TemporalType.TIMESTAMP)	// DATE + TIME으로 날짜 및 시간이 나옴 () => java.util.Date를 import해야 @Temporal 어노테이션 사용 가능 (java.sql.Date X)
//@Temporal(TemporalType.DATE)		// ORACLE에서는 TIMESTAMP와 차이 X
//@Temporal(TemporalType.TIME)		// 날짜는 1970/01/01이고 시간만 맞게 나옴
private Date enrollDate;

👀 PrimaryKey Mapping

GitHub

👉 @Id

💁‍♀️ 해당 필드가 엔티티의 기본키(primary key)를 나타내기 위한 어노테이션

@Id
@Column(name="MEMBER_NO")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="MEMBER_SEQUENCE_GENERATOR")
private int memberNo;

1) Sequence 전략

👉 @SequenceGenerator / @GeneratedValue

💁‍♀️ @SequenceGenerator : 데이터베이스에서 시퀀스를 생성하고 해당 시퀀스를 사용하여 엔티티의 ID를 생성하기 위한 어노테이션
💁‍♀️ @GeneratedValue : 엔티티의 ID를 자동으로 생성하는 데 사용하는 어노테이션

@Entity(name="sequence_member")
@Table(name="TBL_MEMBER_SECTION03_SUBSECTION01")
@SequenceGenerator(
		name="MEMBER_SEQUENCE_GENERATOR", 	// 식별자 생성기 이름
		sequenceName="SEQ_MEMBER_NO", 		// 데이터베이스에 등록 되어있는 시퀀스 이름
		initialValue=5,						// 시퀀스의 시작값(초기값) 설정
		allocationSize=1				
		// 기본 값은 50으로 설정되어 있고 시퀀스 증가와 별개로 메모리에서 식별자를 할당하여 매번 시퀀스를 호출하지 않도록 하는 성능 최적화를 위해 설정 된 값
		// 여러 요청이 동시에 접근해서 데이터를 등록할 때 기본 값이 출돌하지 않은 장점(동시성 문제 해결)이 있지만, 시퀀스가 한 번에 많이 증가하는 점을 염두해야함
		)
public class Member {
	@Id
	@Column(name="MEMBER_NO")
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="MEMBER_SEQUENCE_GENERATOR")
	private int memberNo;
}

2) Table 전략

👉 @TableGenerator / @GeneratedValue

💁‍♀️ @TableGenerator : 엔티티의 키를 생성하기 위한 테이블을 만들고, 이 테이블에서 값을 생성하여 엔티티의 ID에 할당하는 어노테이션
💁‍♀️ @GeneratedValue : 엔티티의 ID를 자동으로 생성하는 데 사용하는 어노테이션

@Entity(name="sequence_table_member")
@Table(name="TBL_MEMBER_SECTION03_SUBSECTION02")
@TableGenerator(
		name="MEMBER_SEQ_TABLE_GENERATOR",
		table="TBL_MY_SEQUENCES",
		pkColumnValue="MY_SEQ_MEMBER_NO",	// PK 컬럼의 이름 지정
		// pkCoulmnName : 시퀀스 컬럼명 (기본 값은 SEQUENCE_NAME)
		// valueColumn : 시퀀스 값 컬럼명 (기본 값은 NEXT_VAL)
		allocationSize=1
		)
public class Member {
	@Id
	@Column(name="MEMBER_NO")
	@GeneratedValue(strategy = GenerationType.TABLE, generator="MEMBER_SEQ_TABLE_GENERATOR")
	private int memberNo;
}

👀 EnumType Mapping

GitHub

👉 @Enumerated

💁‍♀️ 엔티티를 Enum 타입으로 매핑할 때 사용하는 어노테이션

@Column(name="MEMBER_ROLE")
//@Enumerated(EnumType.ORDINAL) // enum의 상수 값을 사용한다는 의미(기본 값) // 장점: 데이터 베이스에 저장되는 데이터의 크기가 작음, 단점: 이미 저장된 enum의 순서 변경 불가
@Enumerated(EnumType.STRING)	// enum의 문자 그대로를 사용한다는 의미		 // 장점: 저장된 enum의 순서가 변경되거나 추가되어도 안전, 단점: 데이터 베이스에 저장되는 데이터의 크기가 ordinal에 비해 큼
private RoleType memberRole;	// String 타입이 아닌 RoleType이라는 enum 타입으로 지정

👀 Access Mapping

GitHub

👉 @Access

💁‍♀️ 엔티티 클래스의 필드와 프로퍼티에 대한 접근 권한을 지정하는 어노테이션
만약 @Access를 설정하지 않으면 @Id의 위치를 기준으로 접근 방식이 설정됨

  • 필드 접근 : 필드에 직접 접근하며 필드 접근 권한이 private여도 접근 가능
  • 프로퍼티 접근 : 접근자(Getter)를 이용하여 접근하는 방식

[1] @Access(AccessType.FIELD) (기본값)

필드에 직접 접근하며 필드 접근 권한이 private여도 접근 가능

@Entity(name="field_access_member")
@Table(name="TBL_MEMBER_SECTION05_SUBSECTION01")
/* 1. 클래스 레벨 : 모든 필드에 대해 적용 */
//@Access(AccessType.FIELD)
public class Member {}
/* 2. 필드 레벨 : 해당 필드의 접근 방식을 필드 접근으로 변경 가능
 * @Id 어노테이션이 필드 레벨에 존재하는 경우 해당 필드는 @Access(AccessType.FIELD)임. 따라서 @Access 어노테이션을 생략해도 무방 */
@Id
@Column(name="MEMBER_NO")
//@Access(AccessType.FIELD)
private int memberNo;

[2] @Access(AccessType.PROPERTY)

접근자(Getter)를 이용하여 접근하는 방식

@Entity(name="property_access_member")
@Table(name="TBL_MEMBER_SECTION05_SUBSECTION02")
//@Access(AccessType.PROPERTY)
/* 클래스 레벨에 @Access(AccessType.PROPERTY)를 작성할 때 주의할 점은
 * @Id 어노테이션이 필드에 있다면 엔티티 매니저 자체를 생성하지 못 하기 때문에 @Id 어노테이션을
 * getter 메소드 위로 옮겨야 함 */
public class Member {}
@Id	// 필드 접근이 아닌 프로퍼티 접근 방식이므로, 필드에 있는 @Id를 getter메소드에 옮겨 붙여줘야함
public int getMemberNo() {
	System.out.println("getMemberNo()를 이용한 access 확인 :3");
	return memberNo;
}

👀 CompositeKey Mapping

GitHub

👉 @Embeddable / @EmbeddedId

💁‍♀️ @Embeddable : 임베드 될 수 있는 복합 키 타입을 지정하기 위한 어노테이션

@Embeddable
public class MemberPK implements Serializable { /* 직렬화 */
	@Column(name="MEMBER_NO")
	private int memberNo;
	@Column(name="MEMBER_ID")
	private String memberId;
}

💁‍♀️ @EmbeddedId : 복합 키 클래스를 매핑하기 위한 어노테이션

/* PK들이 담긴 memberPK 엔티티를 이 클래스의 필드로 선언 */
@EmbeddedId
private MemberPK memberPK;

👉 @IdClass(클래스명.class) / @Id

💁‍♀️@IdClass(클래스명.class) : 복합키를 필드로 정의한 클래스를 해당 클래스에서 매핑하기 위한 어노테이션
💁‍♀️@Id : @IdClass(클래스명.class)이 작성된 클래스 내의 PK인 필드 위에 작성될 어노테이션

@Entity(name="idclass_member")
@Table(name="TBL_MEMBER_SECTION06_SUBSECTION02")
@IdClass(MemberPK.class)
public class Member {
	@Id
	@Column(name="MEMBER_NO")
	private int memberNo;
	@Id
	@Column(name="MEMBER_ID")
	private String memberId;
	@Column(name="PHONE")
	private String phone;
	@Column(name="ADDRESS")
	private String address;
}
  • MemberPK class
public class MemberPK implements Serializable { /* 직렬화 */
	private int memberNo;
	private String memberId;
}

두 방식 모두 복합키 클래스는 영속성 컨텍스트가 관리하지 않는다는 특징이 있으며, 큰 기능적 차이도 존재하지 않음
다만 @Embeddable이 조금 더 객체 지향다운 방법이고, @IdClass는 관계형 데이터 베이스에 가까운 방법

profile
Tiny little habits make me

0개의 댓글