소나무나무
2021. 7. 22. 21:26
객체와 테이블 매핑
- @Entity
- @Entity가 붙은 클래스는 JPA가 관리해서 엔티티라고 부름
- JPA를 사용해서 DB의 테이블과 매핑할 클래스는 필수로 붙혀야함
- 기본 생성자 필수로 있어야 함
- final 클래스, enum, interface, inner 클래스 사용X
- 저장할 필드에 final 사용X
- @Table
- 엔티티와 매핑할 테이블 지정함
- 속성
- name: 매핑할 테이블 이름
- catalog: 데이터베이스 catalog 매핑
- schema: 데이터베이스 schema 매핑
- uniqueConstraints(DDL): DDL 생성 시에 유니크 제약 조건 생성
데이터베이스 스키마 자동 생성
DDL을 애플리케이션 실행 시점에 자동 생성
속성
create: 기존테이블 삭제 후 다시 생성 (DROP + CREATE)
create-drop: create와 같으나 종료시점에 테이블 DROP
update: 변경분만 반영(운영DB에는 사용하면 안됨)
validate: 엔티티와 테이블이 정상 매핑되었는지만 확인
none(아무 문자나 적어도 상관없음): 사용하지 않음
⇒ 운영에서는 쓰지말고, 테스트에서는 validate까지만 쓰자
DDL 생성 기능
제약조건 추가:
@Column(unique = true, length = 10)
DDL 생성 기능은 DDL을 자동 생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않음
- 예) @Table(name="")을 변경하면 DB와 객체 이름을 매핑해야 해서 JPA 실행 로직 변경
- 예) 제약조건을 추가하고 실행했을 때 JPA에서 DDL만 생성하면됨
⇒ DDL 생성 기능을 쓰지 않아도 엔티티에 @Column을 써서 제약조건 같은 중요 정보를 표기해두면 JPQL를 작성할 때 인지하기 편함
필드와 컬럼 매핑
@Column: 컬럼매핑
@Temporal: 날짜 타입 매핑
- LocalDate, LocalDateTime을 사용할 때에는 생략 가능
- TemporalType.DATE: 날짜, 데이터베이스 date 타입과 매핑
(예: 2013–10–11) - TemporalType.TIME: 시간, 데이터베이스 time 타입과 매핑
(예: 11:11:11) - TemporalType.TIMESTAMP: 날짜와 시간, 데이터베이 스
timestamp 타입과 매핑(예: 2013–10–11 11:11:11)
@Enumerated: enum타입 매핑
- EnumType.ORDINAL: enum 순서(Integer)를 데이터베이스에 저장
- EnumType.STRING: enum 이름(String)을 데이터베이스에 저장
- ORDINAL을 사용하면 enum타입을 추가했을 때 순서가 꼬이게 되기 때문에 꼭 STRING을 사용하자
@Lob: BLOB, CLOB 매핑
- 지정할 수 있는 속성이 없음
- 매핑하는 필드가 문자면 CLOB 매핑, 나머지는 BLOB 매핑
@Transient: 특정 필드를 컬럼에 매핑하지 않음(매핑 무시)
- 필드 매핑, 데이터베이스 저장 조회 안됨
- 주로 메모리상에서만 임시로 어떤 값을 보관하고 싶을 때 사용
기본키 매핑
- 직접 할당: @Id만 사용
- 자동 생성(@GeneratedValue)
- IDENTITY: 데이터베이스에 위임, MYSQL에서 사용
- SEQUENCE: 데이터베이스 시퀀스 사용, ORACLE에서 사용
- @SequenceGenerator 필요
- TABLE: 키 생성용 테이블 사용, 모든 DB에서 사용
- @TableGenerator 필요
- AUTO: 데이터베이스 방언에 따라 자동 지정, 실무에선 사용 X
IDENTITY 전략
- 기본키 생성을 데이터베이스에 위임
- 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용(예: MySQL의 AUTO_ INCREMENT)
- INSERT SQL를 실행 후에 ID값을 알 수 있음 ⇒ 커밋하지 않으면 영속성 컨텍스트에 ID값을 넣을 수 없음
- em.persist() 시점에 즉시 INSERT SQL를 실행하고 DB에서 식별자를 조회함
- 버퍼링 방식을 사용할 수 없음
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
SEQUENCE 전략
- 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용
- 시퀀스 값을 먼저 호출을 하고 영속성 컨텍스트에 저장하기 때문에 IDENTITY 방식과 달리 버퍼링 방식이 가능함
@Entity
@SequenceGenerator(
name = “MEMBER_SEQ_GENERATOR",
sequenceName = “MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름
initialValue = 1, allocationSize = 50)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "MEMBER_SEQ_GENERATOR")
private Long id;
SEQUENCE를 여러번 호출하면 성능이 떨어지기 때문에 allocationSize를 사용해 최적화함
DB에 시퀀스를 호출할 때 allocationSize값만큼 증가시켜놓고, 메모리에서 미리 호출한 시퀀스 값을 사용함
메모리에서 allocationSize값을 다 사용했다면 다시 DB에 시퀀스를 allocationSize값만큼 호출함
try { Member member1 = new Member(); member1.setUsername("A"); Member member2 = new Member(); member1.setUsername("B"); Member member3 = new Member(); member1.setUsername("C"); System.out.println("=================="); em.persist(member1); // 1, 51번까지 시퀀스 호출 em.persist(member2); // 메모리에서 호출 em.persist(member3); // 메모리에서 호출 System.out.println("member1 = " + member1.getId()); System.out.println("member2 = " + member2.getId()); System.out.println("member3 = " + member3.getId()); System.out.println("=================="); tx.commit(); }
Table 전략
- 키 생성 전용 테이블을 만들어서 데이터베이스 시퀀스를 흉내내는 전략
- 장점: 모든 데이터베이스에 적용 가능
- 단점: 성능이 좋지 않음(SEQUENCE 전략처럼 성능 최적화를 하자)
- 많이 사용 안하는 전략
@Entity
@TableGenerator(
name = "MEMBER_SEQ_GENERATOR",
table = "MY_SEQUENCES",
pkColumnValue = “MEMBER_SEQ", allocationSize = 1)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "MEMBER_SEQ_GENERATOR")
private Long id;
create table MY_SEQUENCES (
sequence_name varchar(255) not null,
next_val bigint,
primary key ( sequence_name )
)
- 권장하는 식별자 전략
- 기본키 제약조건(NULL 아님, 유일값, 값 변경X)을 차후까지 만족하는 자연키를 찾기 어려움
- 대리키(대체키)를 사용하는 것을 권장
- 권장: Long형(10억 이상 사용하기 위해) + 대체키 + 키 생성전략(시퀀스, UUID 등) 사용