엔티티 매핑

twocowsong·2023년 4월 27일
0

김영한_jpa

목록 보기
5/13

객체와 테이블 매핑

@Entity

  • @Entity가 붙은 클래스는 JPA가 관리, 엔티티라고 합니다.
  • JPA를 사용해서 테이블과 매핑할 클래스는 @Entity 필수
  • 기본 생성자 필수
  • final 클래스, enum, interface, inner 클래스 사용하지 못한다.
@Entity // JPA를 사용하기위해 무조건 필수
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Member {

	@Id // PK
	private Long id;
	private String name;
}

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

  • DDL을 애플리케이션 실행 시점에 자동 생성
  • 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL 생성
  • 이렇게 생성된 DDL은 개발 장비에서만 사용
persistence.xml
	...
	<property name="hibernate.hbm2ddl.auto" value="create" />
	...
옵션설명
create기존테이블 삭제 후 다시 생성 (DROP + CREATE)
create-dropcreate와 같으나 종료시점에 테이블 DROP
update변경분만 반영(운영DB에는 사용하면 안됨)
validate엔티티와 테이블이 정상 매핑되었는지만 확인
none사용하지 않음

• 개발 초기 단계는 create 또는 update
• 테스트 서버는 update 또는 validate
• 스테이징과 운영 서버는 validate 또는 none

> 운영 장비에는 절대 create, create-drop, update 사용하면 안된다.

DDL 생성 기능

DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.

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

@Column으로 DB제약조건을 입력할수있습니다.

필드와 컬럼 매핑

어노테이션설명
@Column컬럼 매핑
@Temporal날짜 타입 매핑
@Enumeratedenum 타입 매핑
@LobBLOB, CLOB 매핑
@Transient특정 필드를 컬럼에 매핑하지 않음(매핑 무시)
@Entity
@Getter
@Setter
public class Member {

	@Id // PK 매핑
	private Long id;

	@Column(name = "name") // DB컬럼명은 name
	private String username;

	private Integer age;

	@Enumerated(EnumType.STRING) // Java Enum을 매핑
	private RoleType roleType;

	@Temporal(TemporalType.TIMESTAMP)
	private Date createdDate;

	@Temporal(TemporalType.TIMESTAMP)
	private Date lastModifiedDate;

	@Lob
	private String description;

	public Member() {
	}
}
name필드와 매핑할 테이블의 컬럼 이름
insertable / updatable해당 컬럼의 INSERT / UPDATE 여부
nullableNotNull제약조건 추가
unique컬럼에 제약조건을 걸때 사용하지만, 이름이 이상하게 생성되어 사용하지않음
columnDefinition데이터베이스 컬럼 정보를 직접 줄 수 있음
precisionBigDecimal 타입에서 사용

@Enumerated 사용시 주의!

@Enumerated(EnumType.STRING)
@Enumerated(EnumType.ORDINAL)
private RoleType roleType;

EnumType이 String과 Ordinal처럼 2개가 있는데 EnumType.ORDINAL로 설정 시 Enum의 값에 순서가 들어가 실제 데이터가 0, 1, 2...가 입력됩니다. 이때 순서가 바뀌거나 신규 추가가 발생시 순서가 꼬이는 상황이 발생되어 EnumType.STRING으로 입력해야 추후 문제가 발생하지 않게됩니다.

Member member = new Member();
member.setId(2L);
member.setUsername("B");
member.setRoleType(RoleType.ADMIN);

em.persist(member);

setRoleType처럼 값을 이력하게되면 아래에 ROLETYPE값처럼 확인 할수 있습니다.

@Temporal

날짜 타입(java.util.Date, java.util.Calendar)을 매핑할 때 사용

import java.time.LocalDate;
import java.time.LocalDateTime;
	...
	private LocalDate localDate;
	private LocalDateTime localDateTime;

위처럼 LocalDate, LocalDateTime을 사용할 때는 생략이 가능합니다.

@Lob

데이터베이스 BLOB, CLOB 타입과 매핑
매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑

@Transient

주로 메모리상에서만 임시로 어떤 값을 보관하고 싶을 때 사용

기본 키 맵핑

기본 키 매핑 어노테이션

@Id : 직접 할당
@GeneratedValue : 자동 생성

	...
     @Id // PK 매핑
	@GeneratedValue(strategy = GenerationType.AUTO) // 방언에 따라 자동 지정, 기본값
	@GeneratedValue(strategy = GenerationType.IDENTITY) // 데이터베이스에 위임
	@GeneratedValue(strategy = GenerationType.SEQUENCE) // 오라클에서 자주 사용 - DB시퀀스 오브젝트에서 사용
	private Long id;
    ...

SEQUENCE를 사용할때는 상단에 시퀀스제네레이터를 선언해야합니다.

@Entity
@SequenceGenerator(name = “MEMBER_SEQ_GENERATOR",
 	sequenceName = “MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
 	initialValue = 1 // DDL 생성 시에만 사용됨, 시퀀스 DDL을 생성할 때 처음 1 시작하는수를 지정한다
  , allocationSize = 1 // 시퀀스 한 번 호출에 증가하는 수(성능 최적화에 사용됨 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값 을 반드시 1로 설정해야 한다
)
public class Member {
	...

IDENTITY전략 특징

영속성 컨텍스트에 1차캐시에 데이터가 등록되기 위해선 PK가 있어야 하는데, IDENTITY로 전략을 하게되면 DB에 INSERT 후에 PK가 설정되게 됩니다.
위와 같은 상황이라면, PK가 없는 상태에서 INSERT가 되어야하는데 JPA와는 맞지 않는상황입니다.

그래서 JPA에서는 IDENTITY가 PK가 될때 em.persist(member); 되는 순간 INSERT 쿼리가 실행되게 됩니다(원래는 commit이 되어야지 SQL저장소에서 한번에 스크립트가 DB에 전송되었던 상황이랑 다르게됩니다.)

SEQUENCE전략 특징

SEQUENCE도 IDENTITY와 비슷합니다. em.persist(member);가 되는 순간 시퀀스에 다음 값을 호출하게됩니다. 하지만 IDENTITY와 다르게 INSERT되는 것이아니라 영속성 컨텍스트에 member.setId(가져온 시퀀스값)이 바인딩 되게 됩니다. IDENTITY와 다르게 DB에는 입력이 되지 않은 상태입니다.

그후 commit()시에 flush가 되게 됩니다.

여기서 만나게 되는 의문점이있는데, 시퀀스에서 조회 후 또 INSERT를 하게되면 DB에 대한 자원낭비가 되지않나라는 의문점을 가지게됩니다. 이를 해결하기위해 @SequenceGenerator 어노테이션에allocationSize 설정값이 있습니다.
이는 미리 시퀀스에서 할당치 만큼 조회하여 가지고있는것입니다.
DB는 한번 호출 시에 이미 할당치 만큼 증가가 되어있고, 웹서버는 메모리에 쌓아두고 있는 상태입니다.

profile
생각하는 개발자

0개의 댓글