💁♀️ 해당 클래스를 엔티티로 설정하기 위한 어노테이션
프로젝트 내에 다른 패키지에도 동일한 엔티티가 존재하는 경우, 해당 엔티티를 식별하기 위한 중복되지 않는 name을 지정해줘야함@Entity(name="section01_member") @Table(name="TBL_MEMBER_SECTION01") public class Member {}
💁♀️ 매핑 될 테이블의 이름을 작성하기 위한 어노테이션
생략 시, 자동으로 클래스의 이름을 테이블의 이름으로 사용
실제로 존재하지 않는 테이블명 작성 시, 새로 테이블을 생성함@Entity(name="section01_member") @Table(name="TBL_MEMBER_SECTION01") public class Member {}
💁♀️ 객체 필드를 테이블의 컬럼에 매핑시켜주는 어노테이션
@Column(name="MEMBER_ID") private String memberId;
주로 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;
💁♀️ 테이블 생성 시 무시되는 컬럼을 표시하기 위한 어노테이션
@Column(name="NICKNAME") @Transient private String nickname;
사용 후, 실제 DB에는 'NICKNAME' 컬럼이 생성되지않음
💁♀️ 데이터베이스와 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;
💁♀️ 해당 필드가 엔티티의 기본키(primary key)를 나타내기 위한 어노테이션
@Id @Column(name="MEMBER_NO") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="MEMBER_SEQUENCE_GENERATOR") private int memberNo;
💁♀️ @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; }
💁♀️ @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; }
💁♀️ 엔티티를 Enum 타입으로 매핑할 때 사용하는 어노테이션
@Column(name="MEMBER_ROLE") //@Enumerated(EnumType.ORDINAL) // enum의 상수 값을 사용한다는 의미(기본 값) // 장점: 데이터 베이스에 저장되는 데이터의 크기가 작음, 단점: 이미 저장된 enum의 순서 변경 불가 @Enumerated(EnumType.STRING) // enum의 문자 그대로를 사용한다는 의미 // 장점: 저장된 enum의 순서가 변경되거나 추가되어도 안전, 단점: 데이터 베이스에 저장되는 데이터의 크기가 ordinal에 비해 큼 private RoleType memberRole; // String 타입이 아닌 RoleType이라는 enum 타입으로 지정
💁♀️ 엔티티 클래스의 필드와 프로퍼티에 대한 접근 권한을 지정하는 어노테이션
만약 @Access를 설정하지 않으면 @Id의 위치를 기준으로 접근 방식이 설정됨
- 필드 접근 : 필드에 직접 접근하며 필드 접근 권한이 private여도 접근 가능
- 프로퍼티 접근 : 접근자(Getter)를 이용하여 접근하는 방식
필드에 직접 접근하며 필드 접근 권한이 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;
접근자(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; }
💁♀️ @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)
이 작성된 클래스 내의 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는 관계형 데이터 베이스에 가까운 방법