[JPA] 엔티티 매핑

 설계적인 측면 (객체와 관계형 데이터베이스를 어떻게 매핑해서 사용하는지)에 관한 공부

 

객체와 테이블 매핑

 

- @Entity : JPA가 관리하는 객체 명시

- 클래스와 테이블을 매핑하기 위하여 클래스에 @Entity를 명시해준다. @Entity가 명시되지 않은 클래스는 JPA가 관리대상으로 생각하지 않기 때문에 JPA를 사용해서 테이블과 매핑하려면 @Entity 어노테이션을 반드시 명시해주어야 한다.

- 기본(public/protected) 생성자가 필수적으로 요구된다.

- DB에 저장할 필드에 final 사용이 불가능하다.

 

- @Table : 엔티티와 매핑할 테이블 지정

- @Table(name = " ")와 같이 매핑할 테이블의 이름을 변경할 수 있다.

 

 

데이터베이스 스키마 자동 생성이란?

 JPA는 애플리케이션 로딩 시점에 DB테이블을 생성(CREATE)하는 기능도 지원한다. 실무가 아닌 개발환경 구축에는 데이터베이스에 별도로 테이블을 구축해줄 필요가 없으므로 유리하다. persistence.xml파일에서 hibernate,hbm2ddl.auto의 value값을 지정해줌으로서 모드를 바꿀 수 있다.

//기존테이블 삭제 후 다시 생성
<property name="hibernate.hbm2ddl.auto" value="create" />

//create와 같으나 종료시점에 drop(테이블 삭제) - 테이트코드에 사용하기 좋음
<property name="hibernate.hbm2ddl.auto" value="create-drop" />

//변경분만 반영(alter. 다만 변경이라고해서 삭제는 안된다-포맷방지)
<property name="hibernate.hbm2ddl.auto" value="update" />

//엔티티와 테이블이 정상 매핑되었는지만 확인. 매핑되지 않으면 오류발생
<property name="hibernate.hbm2ddl.auto" value="validate" />

//주석처리한것과 동일
<property name="hibernate.hbm2ddl.auto" value="none" />

주의) 특히 실무, 운영서버에서 create, create-drop, update를 사용하면 안된다(validate, none) - 그냥 none으로 두고 사용하자. 로딩 시점에 시스템이 자동으로 작성해주는것이 마냥 좋은 것은 아니다.

@Column(unique=true, length=10)
private String name;

또한 column에 옵션을 추가할 수 있다. 

JPA는 생성할때마다 어노테이션을 보고 DDL을 생성하는데 영향을 준다. (DDL을 자동 생성할때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다)

※DDL : CREATE, ALTER와 같이 SCHEMA, TABLE등을 정의하거나 변경할때 사용하는 언어를 지칭

 

 

필드와 컬럼 매핑

1. Member객체를 일반 회원과 관리자로 구분하기
2. 회원 가입일과 수정일 정보 추가
3. 회원을 설명할 수 있는 필드 추가
@Entity 
public class Member { 
 @Id 
 private Long id; 
 
 //객체명은 username으로 쓰고싶은데 db에는 name이라고 컬럼 생성하기 위해
 @Column(name = "name") 
 private String username; 
 
 //Integer형으로 만들면 자동으로 적합한 정수형으로 변환
 private Integer age; 
 
 //Enum형을 DB에서 사용할 수 있게 해줌
 @Enumerated(EnumType.STRING) 
 private RoleType roleType; 
 
 //DATE(날짜), TIME(시간), TIMESTAMP(날짜,시간) 중에서 설정 가능
 @Temporal(TemporalType.TIMESTAMP) 
 private Date createdDate; 
 @Temporal(TemporalType.TIMESTAMP) 
 private Date lastModifiedDate; 
 
 //큰 정보를 넣게 해줌
 @Lob 
 private String description; 
 
 //Getter, Setter… 
}

- @Column 속성

@Column

-@Enumerated 속성

 위 속성의 기본값은 ORDINAL인데 무조건 STRING으로 사용하도록 하자. ORDINAL으로 사용하면 integer로 변환되어 enum에서 지정한 순서가 저장된다. 그런데 enum타입의 순서가 DB연동중에 바뀌면 큰 문제가 발생할 수 있으므로 반드시 STRING으로만 사용하자.

 

-@Transient 속성

엔티티 객체의 데이터와 테이블의 컬럼과 매핑하고 있는 관계를 끊기 위해 사용한다.

 

 

 

매핑 속성 정리

 

 

기본 키 매핑

 

- @Id

 아이디 직접 할당시 사용

 

- @GeneratedValue

 아이디 자동 생성시 사용

 

<옵션>

@GeneratedValue(strategy = GenerationType.AUTO) : 방언에 따라 밑의 3가지중 자동 지정. 기본값
                         = GenerationType.IDENTITY) : 키 생성을 데이터베이스에 위임
                         = GenerationType.SEQUENCE), @SequenceGenerator를 이용하여 테이블마다 시퀀스 관리 : 유일한 값을 순서대로 실행해주는 데이터베이스 오브젝트 사용
                         = GenerationType.TABLE), @TableGenerator : 키 생성 테이블 사용

 

식별자 생성 전략 : 식별자는 NULL이 아니고, 유일해야하고, 변하면 안된다. 그런데 애플리케이션이 존재하는, 최대 수십년의 시간 동안 이러한 조건을 만족하는 자연키를 찾는것은 쉽지 않다. 따라서 대리키(대체키-랜덤값, generatedvalue,uuid 등)를 사용하자.

 

- 저번 포스트에서 언급했었듯, 영속성 컨텍스트에 들어가기 위해서는 무조건 PK값이 있어야 한다. (영속상태가 되기 위해서는 컨텍스트의 1차 캐시에 id값과 Entity정보가 들어가야한다.) 그런데 IDENTITY같은 경우에 DB에 키 생성을 위임하므로 DB에 전달되기 전에는 id정보를 알 수 없다. 그래서 예외적으로 @GeneratedVallue의 strategy가 GenerationType.IDENTITY일 경우에만 em.persist 호출시 커밋하지 않아도 쿼리(INSERT)문을 날리고 db에서 다시 읽어와서 캐시에 넣는 방법을 택한다.