반응형
객체와 테이블 매핑
@Entity
- 선언된 클래스는 JPA가 관리한다. 엔티티라 한다.
- 기본 생성자가 반드시 있어야한다.
- JPA 내부적으로 사용한다. (접근제한 설정은 public 또는 protected 가능)
- final 클래스, enum, interface, inner 클래스에는 @Entity를 사용할 수 없다.
- 저장할 필드에 final 키워드를 사용하면 안된다.
@Entity
속성- name
- JPA에서 사용할 엔티티 이름을 지정한다.
- 기본 설정은 클래스 이름을 그대로 사용한다.
- Member 클래스위에 선언한 경우 Member
- 같은 클래스 이름이 없으면 가급적 기본 값을 사용한다.
- name
@Table
- 엔티티와 매핑할 테이블을 지정한다.
@Table
속성- name
- 매핑할 테이블 이름.
- 기본 설정은 엔티티 이름을 사용한다.
- catalog
- 데이터베이스 catalog 매핑
- schema
- 데이터베이스 schema 매핑
- uniqueConstraints
- DDL 생성 시에 유니크 제약 조건 생성
- name
- 예) 유니크 제약조건 추가(DDL 생성 기능)
@Table(uniqueConstraints = {@UniqueConstraint( name = “NAME_AGE_UNIQUE”, columnNames = {”NAME”, “AGE”})})
데이터베이스 스키마 자동 생성
- JPA는 애플리케이션 실행 시점에 DDL을 자동 생성하는 기능을 지원한다.
- DDL 생성 기능은 DDL을 자동생성할 때만 사용되고 JPA의 실행 로직에는 영향을 주지 않는다.
- 데이터베이스 방언을 활용해서 데이터베이스에 맞는 적절한 DDL을 생성해준다.
- 생성된 DDL은 개발환경, 로컬환경에서 테스트용으로 사용할 수 있다.
- 운영에서 사용하려면 생성된 DDL을 더 다듬어서 사용해야 한다.
hibernate.hbm2ddl.auto
옵션create
- 기존 테이블 삭제 후 다시 생성 (DROP + CREATE)
create-drop
- create와 같으나 종료시점에 테이블 DROP한다.
update
- 추가되는 변경 부분만 반영(운영DB에는 사용하면 안된다)
- alter table
- 기존 컬럼을 삭제하는 것은 DDL이 생성되지 않는다.
validate
- 엔티티와 테이블이 정상 매핑되었는지만 확인한다.
- 정상적으로 매핑되지 않은 경우 에러 발생한다.
none
- DDL 자동 생성 기능을 사용하지 않는다.
- 이 옵션은 실질적으로 존재하지 않는다.
- JPA가 인식할 수 없음, 옵션에 해당하지 않는 문자를 입력한 것과 마찬가지이다.
- 관례상 옵션을 사용안하는 것을 none을 적어서 표현하기도 하며 주석 처리를 하기도 한다.
스키마 자동 생성 옵션 주의점
- 운영환경에서는 절대 create, create-drop, update를 사용하면 안된다.
- 개발 초기 단계는 create 또는 update
- 테스트 서버는 update 또는 validate
- 스테이징과 운영서버는 validate 또는 none
- 가장 권장하는 것은 DDL 스크립트를 만들어서 DB에 직접 적용하는 것이 좋다.
- 운영환경에서 drop, alter를 모든 개발자가 마음대로 할 수 없도록 권한을 분리하여 계정별로 운영, 관리하는 것 또한 중요하다.
필드와 컬럼 매핑
@Column
- 컬럼을 매핑할 떄 사용한다.
name
- 객체의 필드와 매핑할 테이블의 컬럼이름을 매핑하는 데 사용한다. 기본값은 객체의 필드 이름으로 설정되어 동작한다.
- 객체 필드명과 DB 컬럼명이 다른 경우, 객체 필드명을 DB컬럼명으로 인식하도록 매칭시킬 수 있다.
insertable
- 컬럼 등록 가능 여부. 기본 값은 TRUE
- 등록할 때 쿼리에 이 컬럼을 포함할 것인가 안할 것인가에 대한 것이다.
updateable
- 컬럼 변경 가능 여부. 기본 값은 TRUE
- 수정할 때 쿼리에 이 컬럼을 포함할 것인가 안할 것인가에 대한 것이다.
- (DDL)
length
- DDL과 관련된 속성이다.
- 문자 길이 제약조건, String 타입에만 사용한다. 기본 값은 255 이다.
- (DDL)
nullable
- DDL과 관련된 속성이다.
- null 값의 허용 여부를 설정한다. false로 설정하면 DDL 생성 시에 not null 제약조건이 붙는다.
- 예) 제약조건 추가: 회원 이름은 필수, 10자 초과 불가능(DDL 생성 기능)
@Column(nullable = false, length = 10)
- (DDL)
unique
- DDL과 관련된 속성이다.
@Table
의 uniqueConstraints와 같지만 한 컬럼에 간단히 유니크 제약조건을 걸 때 사용한다.
- 잘 사용하지는 않는다. 제약조건 이름이 이상하게 생성된다. 또한 여러 컬럼에 대해서 unique 제약조건을 걸 수 없다.
@Table
의uniqueConstraints 는 제약조건 이름까지 설정할 수 있고 여러 컬럼에 대해서도 제약조건을 걸 수 있어서@Table
의uniqueConstraints 를 사용하는 것이 좋다.
- (DDL)
columnDefinition
- DDL과 관련된 속성이다.
- 데이터베이스 컬럼 정보를 직접 설정해줄 수 있다.
- 예) 컬럼의 길이를 100으로 하고 컬럼의 기본 값으로 EMPTY 라고 설정한다.
@Column(columnDefinition = "varchar(100) default 'EMPTY'")
precision
, (DDL)scale
- BigDecimal 타입에서 사용한다(BigInteger도 사용할 수 있다).
- precision은 소수점을 포함한 전체 자릿수를, scale은 소수의 자릿수다.
- 참고로 double, float 타입에는 적용되지 않는다.
- 아주 큰 숫자나 정밀한 소수를 다루어야 할 때만 사용한다.
- 기본값
- precision=19
- scale=2
@Enumerated
- enum 타입을 매핑하기 위해서 사용한다.
- 일반적으로 DB에는 enum 타입이 존재하지 않기 때문에 enum 타입은 이를 사용해서 매핑해야한다.
value
EnumType.ORDINAL
- enum 순서를 데이터베이스에 저장. 기본 값으로 설정되어 있다.
- 숫자 타입으로 저장된다.
EnumType.STRING
- enum 이름을 데이터베이스에 저장.
- 문자 타입으로 저장된다.
- 기본값은
EnumType.ORDINAL
이다. 그러나 절대로EnumType.ORDINAL
를 사용하면 안된다.
- 첫 번째 또는 중간에 EnumType이 추가되는 경우, enum 타입의 순서가 변경되어 기존 데이터가 가지는 순서가 모두 영향을 받아서 엉뚱한 데이터가 조회되고 사용되는 상황이 발생한다.
- 따라서 enum 타입을 사용하는 경우에는 반드시 값을
EnumType.STRING
로 설정하여 사용해야 한다.
@Temporal
- 날짜 타입(java.util.Date, java.util.Calendar)을 매핑하기 위해서 사용한다.
- 단, LocalDate(년월일), LocalDateTime(년월일시)을 사용할 때는 생략 가능하다.
- 최신 하이버네이트에서 지원한다.
- 자바에서는 날짜 타입에 날짜와 시간이 모두 존재한다.
- DB에서는 날짜, 시간, 위치 이런 것들을 모두 구분해서 사용하기 때문에 어떤 방식으로 날짜를 표현할지 정해주어야 한다. 이러한 경우 사용한다.
value
TemporalType.DATE
- 날짜, 데이터베이스 date 타입과 매핑
- 예) 2013–10–11
TemporalType.TIME
- 시간, 데이터베이스 time 타입과 매핑
- 예) 11:11:11
TemporalType.TIMESTAMP
- 날짜와 시간, 데이터베이스 timestamp 타입과 매핑
- 예) 2013–10–11 11:11:11
@Lob
- 데이터베이스 BLOB, CLOB 타입과 매핑하기 위해서 사용한다.
- 일반적인 데이터타입의 범위를 넘어서는 데이터라면 Lob타입을 사용한다.
- 매핑하는 필드 타입이 문자면 CLOB 매핑, 나머지는 BLOB 매핑
CLOB
- String, char[], java.sql.CLOB
BLOB
- byte[], java.sql.BLOB
@Transient
- 특정 필드를 DB 컬럼에 매핑하지 않음(매핑 무시)
- 데이터베이스에 저장되거나 조회되지 않는다.
- DB와 관계없이 메모리에서만 임시로 어떤 값을 보관하고 싶을 때 사용한다.
기본 키 매핑
@Id
- 값을 직접 할당
- 여러 코드성 데이터를 조합해서 키를 만드는 경우 사용한다.
@GeneratedValue
- int 보다 Integer를 사용하는 것이 좋다. 그러나 Integer도 10억이 넘어가면 다시 한 바퀴 돈다. 결론은 Long을 사용하는 것이 좋다.
- 값을 자동으로 생성
strategy
IDENTITY
- 이 전략은 기본 키 생성을 데이터베이스에 위임한다.
- 주로 MySQL, PostgreSQL, SQL Server, DB2에서 사용
- 예) MySQL의 AUTO_ INCREMENT
- 주의점
- 영속성 컨텍스트에서 관리되려면 PK 값이 있어야 한다.
- 1차 캐시에 저장되는
@Id
는 DB의 PK 값이다.
- 1차 캐시에 저장되는
- 그러나 이 전략은 DB에 값이 생성될 때 PK 값을 알 수 있다.
IDENTITY
전략은 특별하게 트랜잭션 커밋 시점이 아니라, em.persist() 시점에 즉시 INSERT SQL 실행하고 DB에서 식별자를 조회한다.
- 따라서 SQL을 모아서 처리하는 것은
IDENTITY
전략에서는 불가능하다.
- 영속성 컨텍스트에서 관리되려면 PK 값이 있어야 한다.
SEQUENCE
- 이 전략은 데이터베이스 시퀀스 오브젝트 사용해서 기본 키를 생성한다.
- 데이터베이스 시퀀스는 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트이다.
- 오라클, PostgreSQL, DB2, H2 데이터베이스에서 사용
- 예) 오라클 시퀀스
- 주의점
- 영속성 컨텍스트에서 관리하기 위해서 em.persist() 호출 시점에 먼저 시퀀스를 가져온 후 1차 캐시에 저장한다.
- INSERT SQL 은 실행되지 않는다. 시퀀스를 통해서 PK 값을 얻어올 수 있다.
- 일반적으로 JPA가 동작하는 것과 같이 트랜잭션 커밋 시점에 SQL이 실행된다.
- SQL을 모아서 처리하는 것이 가능하다.
- 그러나 성능상으로 따지고 보면 네트워크 통신이 2번 일어난 것이다.
- 시퀀스를 통해서 PK 조회
- INSERT SQL 실행
- 이러한 관점에서 성능을 향상에 사용할 수 있는 속성이
@SequenceGenerator
의allocationSize
속성이다.- 저장할 때마다 시퀀스를 통해서 PK 값을 조회해온다면 성능상 문제가 생길 수 있다.
- 미리 사용할 시퀀스 범위를 할당받아 사용한다면 불필요한 네트워크 통신은 발생하지 않는다.
- 예)
allocationSize
를 50으로 설정- 한 번의 시퀀스 호출로 50번까지 사용할 수 있다.
- 따라서 여러 개 저장한다고 해도 50개 미만이라면 별도의 네트워크 통신(시퀀스 호출) 없이 PK를 설정하여 처리할 수 있다.
- 동시성 이슈 없이 사용할 수 있다.
- 미리 시퀀스 값을 확보하여 메모리에 올려두는 방식이기 때문에 시퀀스가 겹치지 않는다.
@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; ... ... ... }
public class JpaMain { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); try { Member memberA = new Member(); memberA.setUsername("testA"); Member memberB = new Member(); memberB.setUsername("testB"); Member memberC = new Member(); memberC.setUsername("testC"); //시퀀스 호출은 1회 발생, 시퀀스는 allocationSize 크기만큼 메모리에 저장해서 사용 em.persist(memberA); //PK 1, 51 em.persist(memberB); //PK 2, MEMORY em.persist(memberC); //PK 3, MEMORY tx.commit(); } catch (Exception e) { tx.rollback(); } finally { em.close(); } emf.close(); } }
- 영속성 컨텍스트에서 관리하기 위해서 em.persist() 호출 시점에 먼저 시퀀스를 가져온 후 1차 캐시에 저장한다.
@SequenceGenerator
를 이용하여 테이블별로 사용할 시퀀스를 지정할 수 있다.
@SequenceGenerator
name
- 식별자 생성기 이름을 의미한다. 기본값 필수
sequenceName
- 데이터베이스에 등록되어 있는 시퀀스 이름을 설정한다.
- 기본 값은 hibernate_sequence
initialValue
- DDL 생성 시에만 사용된다.
- 시퀀스 DDL을 생성할 때 처음 시작하는 수를 설정한다.
- 기본 값은 1이다.
allocationSize
- 시퀀스 한 번 호출에 증가하는 수를 설정한다.
- 성능 최적화에 사용된다. 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다.
- 기본 값은 50이다.
catalog
,schema
- 데이터베이스 catalog, schema 이름을 의미한다.
- 예)
@Entity @SequenceGenerator( name = "MEMBER_SEQ_GENERATOR", sequenceName = "MEMBER_SEQ", //매핑할 데이터베이스 시퀀스 이름 initialValue = 1, allocationSize = 1) public class Member { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_SEQ_GENERATOR") private Long id; ... ... ... }
- 이 전략은 데이터베이스 시퀀스 오브젝트 사용해서 기본 키를 생성한다.
TABLE
- 이 전략은 키 생성용 테이블을 하나 만들어서 데이터베이스 시퀀스를 흉내내는 전략이다.
- 장점은 모든 DB에서 적용 가능하다.
- 단점은 성능이 문제가 된다.
@TableGenerator
를 이용하여 사용할 테이블을 설정할 수 있다.
@TableGenerator
name
- 식별자 생성기 이름을 의미한다. 기본값 필수
table
- 기본 키를 생성하는 테이블 이름을 의미한다.
- 기본 값은 hibernate_sequences
pkColumnName
- 키 생성용 테이블의 시퀀스 이름이 저장되는 컬럼명을 의미한다.
- 기본 값은 sequence_name
valueColumnNa
- 키 생성용 테이블의 시퀀스 값이 저장되는 컬럼명을 의미한다.
- 기본 값은 next_val
pkColumnValue
- 키 생성용 테이블에서 키로 사용할 시퀀스 이름을 의미한다.
- 기본 값은 엔티티 이름으로 설정된다.
initialValue
- 초기 값, 마지막으로 생성된 값이 기준이다.
- 기본 값은 0이다.
allocationSize
- 시퀀스 한 번 호출에 증가하는 수를 설정한다.
SEQUENCE
전략에서 사용되는 특징과 동일하다.- 성능 최적화에 사용된다. 데이터베이스 시퀀스 값이 하나씩 증가하도록 설정되어 있으면 이 값을 반드시 1로 설정해야 한다.
- 기본 값은 50이다.
catalog
,schema
- 데이터베이스 catalog, schema 이름을 의미한다.
- (DDL)
uniqueConstraints
- 유니크 제약 조건을 지정할 수 있다.
- 예)
@Entity @TableGenerator( name = "MEMBER_SEQ_GENERATOR", table = "MY_SEQUENCES", // 테이블 이름 pkColumnValue = "MEMBER_SEQ", allocationSize = 1) // PK 컬럼 이름 public class Member { @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "MEMBER_SEQ_GENERATOR") private Long id; ... ... ... }
AUTO
- 기본 값으로 설정되어 있다.
- DB 방언에 따라
IDENTITY
,SEQUENCE
,TABLE
중에 자동 지정한다.- 예) ORACLE이면
SEQUENCE
전략으로 동작
- 예) ORACLE이면
[참고자료]
자바 ORM 표준 JPA 프로그래밍 - 기본편, 김영한
반응형
'Java > ORM' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 영속성 전이 (0) | 2022.04.19 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] 프록시와 연관관계 관리 (0) | 2022.04.15 |
[자바 ORM 표준 JPA 프로그래밍] 상속관계 매핑 (0) | 2022.04.06 |
[자바 ORM 표준 JPA 프로그래밍] 연관관계 매핑 (0) | 2022.04.03 |
[자바 ORM 표준 JPA 프로그래밍] JPA의 영속성 관리 (0) | 2022.03.18 |