엔티티와 테이블을 정확히 매핑하는 것은 JPA를 사용 할 때 가장 중요한 일 중 하나 입니다.
JPA에서 지원하는 매핑 어노테이션은 크게 4가지로 분류할 수 있습니다.
@Entity
, @Table
@Id
@Column
@ManyToOne
, @JoinColumn
JPA를 사용해서 테이블과 매핑할 클래스는 @Entity
을 필수로 붙여야 합니다.
@Entity
적용 시 주의사항은 다음과 같습니다.
기본 생성자가 하나도 없으면 기본 생성자를 자동으로 만들며, 만약 생성자를 하나 이상 만들면 기본 생성자를 직접 만들어 줘야합니다.
@Table
은 엔티티와 매핑할 테이블을 지정합니다.
@Enumerated
으로 매핑 하여야 합니다.@Temporal
을 사용해서 매핑합니다.@Lob
을 사용하여 CLOB, BLOB 타입으로 매핑 할 수 있습니다.스프링에서는 application.yaml 또는 application.properties를 통해 hibernate 설정으로 데이터베이스 스키마 자동 생성에 관한 설정을 할 수 있습니다.
@Column(name = "NAME", nullable = false, length = 10)
private String name;
@Column
의 속성 값으로 DDL 생성 시의 제약조건을 추가할 수 있습니다.
@Table(name = "MEMBER", uniqueConstraints = {@UniqueConstraint (
name = "NAME_AGE_UNIQUIE",
columnNames = {"NAME", "AGE"} ) } )
@UniqueConstraint
로 테이블에도 유니크 제약조건을 추가할 수 있습니다.
데이터베이스 마다 기본 키를 생성하는 방식이 서로 다릅니다.
JPA에서는 아래와 같은 기본 키 생성 전략을 제공합니다.
데이터베이스 벤더마다 지원하는 방식이 달라, SEQUENCE나 IDENTITY 전략은 사용하는 데이터베이스에 의존합니다.
그러나 TABLE 전략은 키 생성용 테이블을 하나 만들어 두고 시퀀스 처럼 사용하는 방법입니다.
이 전략은 테이블을 사용하므로 모든 데이터베이스에서 사용할 수 있습니다.
@Id
적용 가능 자바 타입은 아래와 같습니다.
IDENTITY는 기본 키 생성을 데이터베이스에 위임하는 전략입니다.
IDENTITY 전략의 특징은 아래와 같습니다.
persist()
를 호출하는 즉시 INSERT SQL이 데이터베이스에 전달 됩니다. 그렇기 때문에 이 전략은 트랜잭션을 지원하는 쓰기 지연이 동작하지 않습니다.SEQUENCE 전략은 유일한 값을 순서대로 생성하는 데이터베이스 오브젝트를 사용하여 기본 키를 생성하는 전략입니다.
persist()
를 호출할 때 먼저 데이버베이스 시퀀스를 사용해서 식별자를 조회합니다.
그리고 조회한 식별자를 엔티티에 할당한 후 엔티티를 영속성 컨텍스트에 저장합니다.
후 트랜잭션을 커밋해서 플러시가 일어나면 엔티티를 데이터베이스에 저장합니다.
💡 SquenceGenerator.
allocationSize
는 최적화를 위해 기본값이 50으로 설정되어 있습니다. allocationSize 값이 50이면 시퀀스를 한 번에 50 증가 시킨 다음에 1~50까지는 메모리에서 식별자를 할당합니다. 그리고 51이 되면 시퀀스 값을 100으로 증가 시킨 다음 이를 반복합니다. 이 최적화 방법은 시퀀스 값을 선점 하므로 여러 JVM이 동시에 동작 해도 기본 키 값이 충돌하지 않는 장점이 있습니다. 반면에 데이터베이스에 직접 접근해서 데이터를 등록할 때 시퀀스 값이 한번에 많이 증가한다는 점을 염두 해 두어야 합니다. 참고로 앞서 설명한hibernate.id.new_generator_mappings
속성을true
로 설정해야 지금까지 설명한 최적화 방법이 적용된다.
TABLE 전략은 키 생성 전용 테이블을 하나 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어 데이터베이서 시퀀스를 흉내내는 전략입니다. 이 전략은 테이블을 사용하므로 모든 데이터베이스에 적용할 수 있습니다.
💡 TABLE 전략은 값을 조회하면서 SELECT 쿼리 를 사용하고 다음 값으로 증가시키기 위해 UPDATE 쿼리를 사용합니다. 이 전략은 SEQUENCE 전략과 비교해서 데이터베이스와 한번 더 통신하는 단점이 있습니다. TABLE 전략을 최적화하려면
TableGenerator.allocationSize
를 사용하면 됩니다.
AUTO 전략은 데이터베이스 방언에 따라 앞에서 나온 기본 키 생성 전략 중 하나를 자동으로 선택합니다.
이 전략의 장점은 데이터베이스를 변경해도 코드를 수정할 필요가 없다는 것입니다.
SEQUENCE나 TABLE 전략이 선택되면 시퀀스나 키 생성용 테이블을 미리 만들어 두어야 합니다.
persist()
를 호출한 직후에 발생하는 일을 식별자 할당 전략 별로 정리하면 아래와 같습니다.
persist()
를 호출하기 전에 애플리케이션에서 직접 식별자 값을 할당해야 합니다. 만약 식별자 값이 없으면 예외가 발생합니다.기본 키는 다음 3가지 조건을 모두 만족해야 합니다.
기본 키 선택 전략은 크게 2가지가 있습니다.
비즈니스적 환경은 언제나 변하기 때문에 현재는 물론이고 미래가지 충족하는 자연키를 찾는 것은 쉽지 않습니다. 대리 키는 비즈니스와 무관한 임의의 값이므로 요구사항이 변경되어도 기본 키가 변경되는 경우는 드뭅니다.
그렇기 때문에 자연 키보다는 대리 키의 사용을 권장합니다.
@Column
은 객체 필드를 테이블 컬럼에 매핑 합니다.
@Column
을 자바 기본 타입 필드 위에서 사용할 때는 nullable = true가 기본 값이므로 기본 타입에 null 값이 들어갈 수 있습니다. 그렇기 때문에 기본 타입에 @Column
을 사용하면 nullable = false로 지정하는 것이 안전합니다.
EnumType.ORDINAL
은 enum에 정의된 순서대로 데이터베이스에 저장됩니다.
EnumType.STRING
은 enum 이름 그대로 문자로 데이터베이스에 저장됩니다.
💡 기본 값인 ORDINAL은 사이에 enum이 하나 추가되서 설정되면 기존에 있던 정보와 데이터베이스의 정보가 달라질 수 있기 때문에 주의해서 사용해야 합니다.
날짜 타입을 매핑할 때 사용합니다.
자바의 Date 타입에는 년월일 시분초가 있지만 데이터베이스에는 date, time, timestamp라는 세 가지 타입이 별도로 존재합니다.
@Temporal
을 생략하면 자바의 Date와 가장 유사한 timestamp로 정의 됩니다. 다른 예약어를 사용하는 데이터베이스에서는 데이터베이스 방언에 따라 자동으로 해당하는 예약어로 설정 됩니다.
데이터베이스 BLOB, CLOB 타입과 매핑합니다.
@Lob
에는 지정할 수 있는 속성이 없습니다.
대신에 매핑하는 필드 타입이 문자면 CLOB으로 매핑하고 나머지는 BLOB으로 매핑합니다.
이 필드는 매핑하지 않으며, 데이터베이스에 저장하지 않고 조회하지도 않습니다.
객체에 임시로 어떤 값을 보관하고 싶을 때 사용합니다.
JPA가 엔티티 데이터에 접근하는 방식을 지정합니다.
AccessType.FIELD
로 지정합니다. 필드에 직접 접근하며, 필드 접근 권한이 private
이어도 접근할 수 있습니다.AccessType.PROPERTY
로 지정합니다. 접근자(Getter)를 사용합니다.설정하지 않으면 보통 @Id
의 위치를 기준으로 접근 방식이 설정되며, 함께 사용할 수도 있습니다.