엔티티와 테이블을 매핑하는 어노테이션에 대해서 알아보려고 합니다.
JPA는 다양한 매핑 어노테이션을 지원하는데 크게 4가지로 분류할 수 있습니다
- 객체와 테이블 매핑
- @Entity
- @Table
- 기본 키 매핑
- @Id
- 필드와 컬럼 매핑
- @Column
- 연관관계 매핑
- @ManyToOne, @JoinColumn
- 연관관계 매핑은 양이 많아 다른 게시물로 정리하도록 하겠습니다.
객체와 테이블 매핑
@Entity
- JPA를 사용해서 테이블과 매핑할 클래스에 @Entity 를 붙입니다.
- JPA가 관리하는 객체를 Entity라 합니다.
name 속성
- JPA에서 사용할 엔티티 이름을 지정합니다.
- 보통 기본값인 클래스 이름을 사용합니다.
- 다른 패키지에 이름이 같은 엔티티클래스가 존재한다면 이름을 지정해서 충돌을 피해야 합니다.
주의사항
- 기본 생성자가 필수입니다.
- 파라미터가 없는 public이나 protected 생성자여야 합니다.
- final, enum, interface, inner 클래스에는 사용할 수 없습니다.
- DB에 저장할 필드에 final을 사용하면 안됩니다.
@Table
- 엔티티와 매핑할 데이터베이스 테이블을 지정합니다.
- 생략하면 엔티티 이름을 테이블 이름으로 사용합니다.
name 속성
- 매핑할 테이블 이름을 설정합니다.
- 기본값은 엔티티 이름입니다.
catalog 속성 , schema 속성
- catalog 기능이 있는 데이터베이스에서 catalog를 매핑합니다.
- schema 기능이 있는 데이터베이스에서 schema를 매핑합니다.
uniqueConstraints 속성
- DDL 생성 시에 유니크 제약조건을 만듭니다.
- 2개 이상의 복합 유니크 제약조건도 만들 수 있습니다.
- 이 기능은 스키마 자동생성 기능을 사용해서 DDL을 만들 때만 사용됩니다.
- JPA를 통해서 테이블을 만들때 적용되는 것이지 미리 만들어둔 테이블에는 적용되지 않습니다.
데이터베이스 스키마 자동 생성
- JPA는 데이터베이스 스키마를 자동으로 생성하는 기능을 지원합니다.
- 클래스 매핑정보와 데이터베이스 방언을 사용해서 데이터베이스 스키마를 생성합니다.
- hibernate 설정을 해주어야합니다.
- 옵션
- create
- 기존 테이블을 삭제하고 새로 생성합니다.
- DROP + CREATE
- create-drop
- CREATE와 같지만 애플리케이션 종료 시 생성한 DDL을 제거합니다.
- CREATE + DROP
- update
- 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 변경 사항만 수정합니다.
- validate
- 데이터베이스 테이블과 엔티티 매핑정보를 비교해서 차이가 있으면 경고를 남기고 애플리케이션을 실행하지 않습니다.
- 차이가 있다해서 DDL을 따로 수정하지는 않습니다.
- none
- 자동 생성 기능을 사용하지 않습니다.
- create
- 사용 시 주의사항
- DDL을 수정하는 옵션은 운영 서버에서 사용하면 안됩니다. 개발 단계에서만 사용해야합니다.
- 추천하는 방식
- 개발 초기 : create or update
- 초기화 상태로 자동화된 테스트를 진행하는 개발자 환경 및 CI 서버 : create or create-drop
- 테스트 서버 : update or validate
- 스테이징과 운영서버 : validate or none
- 사실 로컬을 제외한 개발 등의 서버는 직접 스크립트를 짜서 데이터베이스에서 반영하는 것을 권장
- 옵션
// 스프링부트 application.yml 기준
spring: jpa: hibernate: ddl-auto: 옵션 설정
기본 키 매핑
직접 할당
- 기본키를 어플리케이션에서 직접 할당합니다.
- 기본키로 사용할 엔티티 필드에 @Id만을 사용하고, 애플리케이션에서 직접 식별자를 만들어 넣는 방식입니다.
자동 생성
- 대리 키 사용 방식 입니다.
- @Id와 함께 @GeneratedValue를 함께 사용합니다.
IDENTITY
- 기본 키 생성을 데이터베이스에 위임하는 전략입니다.
- 주로 MySQL, PostgreSQL, SQL Server, DB2 에서 사용합니다.
- MySQL 같이 AUTO_INCREMENT 등이 있으면 그것을 사용합니다.
- 데이터베이스에 값을 저장하고 나서야 기본키 값을 구할 수 있습니다.
- 데이터베이스가 기본키를 설정하기 때문에 데이터베이스에 값을 저장한 이후에야 애플리케이션은 키본키 값을 알 수 있습니다.
- 이러한 이유로 이 전략에서 em.persist()를 하면 바로 쿼리를 데이터베이스로 날립니다.(트랜잭션을 지원하는 쓰기전략 지원 x)
- 다만 select 쿼리는 보내지 않는데, 그 이유는 JDBC3에 추가된 Statement.getGeneratedKeys()를 사용해서 데이터를 저장과 동시에 생성된 기본키 값을 얻어오기 때문입니다. 하이버네이트는 이 메소드를 사용해서 데이터베이스와 한 번만 통신을 합니다.
SEQUENCE
- 데이터베이스 시퀀스란 유일한 값을 순서대로 생성하는 특별한 데이터베이스 오브젝트입니다.
- SEQUENCE 전략은 이 데이터베이스 시퀀스를 사용해서 기본 키를 생성합니다.
- 시퀀스를 지원하는 Oracle, PostgreSQL, DB2, H2 데이터베이스 등에서 사용할 수 있습니다.
- 작동 순서
- em.persist()를 호출할 때 먼저 데이터베이스에서 시퀀스를 사용해 식별자를 조회합니다.
- IDENTITY와 달리 이때 INSERT 가 날라가지 않습니다.
- 조회한 식별자를 엔티티에 할당한 후에 엔티티를 영속성 컨텍스트에 저장합니다.
- 이후 트랜잭션을 커밋해서 flush가 일어나면 엔티티를 데이터베이스에 저장합니다.
- em.persist()를 호출할 때 먼저 데이터베이스에서 시퀀스를 사용해 식별자를 조회합니다.
- @SequenceGenerator
- 데이터베이스 시퀀스를 매핑합니다.
- Sequence 전략을 사용하면 데이터베이스와 2번 통신합니다.
- 식별자를 구하기 위해 데이터베이스 시퀀스 조회 + 조회환 시퀀스를 기본키 값으로 사용하는 엔티티 저장
- 10번만 저장해도 20번을 데이터베이스와 통신합니다.
- 시퀀스에 접근하는 횟수를 줄이기 위해 allocationSize 속성을 이용합니다.
- 속성에 들어있는 값만큼 한번에 데이터베이스에서 증가시킨 후, 매번 데이터베이스에서 접근하지 않고 그 수만큼 메모리에서 식별자를 할당합니다.
- 예를 들어 값이 50이면, 한번에 50만큼 시퀀스를 증가시키고 DB에서 50만큼 가져와 메모리에서 할당한 후, 가져온 시퀀스를 다 사용하면 다시 증가시키고 가져와서 사용하는 방식입니다.
- 일종의 최적화 방법입니다.
- 속성
TABLE
- 키 생성 전용 테이블을 만들어서 데이터베이스 시퀀스를 흉내내는 전략
- 테이블을 사용하므로 모든 데이터베이스에 적용할 수 있습니다.
- 시퀀스 대신에 테이블을 사용한다는 것만 제외하면 SEQUENCE 전략과 내부 동작방식이 동일합니다.
- 하나의 키 생성 전용 테이블을 여러 엔티티에서 로우만 다르게 공용하여 사용할 수 있습니다.
-
{pkColumnName} {valueColumnName} pkColumnValue1 2 pkColumnValue2 15 pkColumnValue3 40
-
- 속성
AUTO
- 선택한 데이터베이스 방언에 따라 위의 세가지 전략 중 하나를 자동으로 선택합니다.
- 오라클의 경우 SEQUENCE, MySQL의 경우 IDENTITY를 사용하는 등
- @GeneratedValude의 기본값은 AUTO 입니다.
- 키 생성 전략이 확정되지 않은 개발 초기 단계나 프로토타입 개발 시 편리하게 사용할 수 있습니다.
- SEQUENCE나 TABLE 전략이 선택되는 경우, 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 하지만 스키마 자동 생성 기능을 사용한다면 하이버네이트가 기본값을 사용해서 적절하게 만들어 줍니다.
필드와 컬럼 매핑
@Column
- 객체 필드를 테이블 컬럼에 매핑합니다.
- 주로 사용되는 속성은 name, nullable 입니다.
- insertable, updatable 속성은 데이터베이스에 저장되어있는 정보를 읽기만 하고 실수로 변경하는 것을 방지하고 싶을 때 false로 바꾸어 사용합니다.
- unique는 키가 랜덤한 이름으로 나오기 때문에 잘 사용하지 않습니다.
- 대신 @Table에 uniqueConstrains 옵션을 주면 이름을 설정할 수 있어서 이 방법을 더 많이 사용합니다.
- 필드에 @Column을 생략하더라도 테이블 컬럼으로 등록됩니다.
- 주의할 점은 자바 primitive 타입의 경우 null 값이 허용 안되기 때문에 JPA에서 자동으로 not null 제약을 걸어줍니다.
- 다만 primitive 타입에 not null 제약조건이 없는 @Column만 붙일 경우, nullable의 기본값이 true이기 때문에 false로 명시적으로 적어주는 것이 안전합니다.
@Enumerated
- 자바 enum 타입을 매핑할 때 사용합니다.
- value를 STRING으로 사용하도록 합시다!!!!
@Temporal
- 날짜 타입인 java.util.Date, java.util.Calendar를 매핑할 때 사용합니다.
- 어노테이션을 생략하면 자바의 Date와 가장 유사한 timestamp로 정의됩니다.
- LocalDate, LocalDateTime을 사용할 때는 어노테이션을 생략해도 됩니다.
@Lob
- 데이터베이스 blob과 clob 타입과 매핑합니다.
- 매핑하는 필드 타입이 문자면 CLOB, 나머지는 BLOB으로 매핑합니다.
@Transient
- 필드 매핑을 하지 않을 때 사용합니다.
- 데이터베이스에 저장되거나 조회되지 않습니다.
- 주로 메모리 상에서 객체에 임시로 값을 보관하고 싶을 때 사용합니다.
@Access
- JPA가 엔티티 데이터에 접근하는 방식을 지정합니다.
- 생략 시 @Id 위치를 기준으로 접근 방식이 설정됩니다.
- 접근 방식
- 필드 접근
- @Access(AccesType.FIELD)
- 필드 접근 권한이 private이여도 필드에 직접 접근합니다.
- @Id가 필드에 붙어있는 경우, 생략 가능합니다.
- 프로퍼티 접근
- @Access(AccesType.PROPERTY)
- Getter를 사용해서 접근합니다.
- @Id가 Getter에 붙어있는 경우, 생략 가능합니다.
- 필드 접근
'Spring Framework > JPA' 카테고리의 다른 글
@GeneratedValue 로 UUID 사용하기 (0) | 2022.06.13 |
---|---|
Transaction (트랜잭션) (0) | 2022.06.10 |
영속성 관리 (0) | 2022.06.10 |
데이터베이스 방언 (Dialect) (0) | 2022.06.10 |
JPA 소개 (0) | 2022.06.10 |
댓글