자바 ORM 표준 JPA 프로그래밍 - 기본편 : Entity Mapping

jkky98·2024년 9월 26일
0

Spring

목록 보기
48/77

@Entity

JPA의 시작이라고 볼 수 있는 엔티티를 설정하기 위해 클래스에 @Entity 애노테이션을 붙여 JPA가 관리할 수 있도록 한다.

  • 기본 생성자 필수(public or protected)
  • final, enum, interface, inner 사용 불가
  • DB에 저장할 필드 final 사용 불가
  • 속성 name으로 하여금 엔티티 이름 따로 설정가능하지만 보통 기본값 사용(클래스명 이용)

@Table

엔티티와 매핑할 테이블을 지정할 수 있음. 엔티티 이름이 OrderItem이라면 기본적으로 테이블 이름은 order_item이 된다.(소문자)

  • name 속성 : 매핑할 테이블 이름 지정 가능 (기본값 엔티티 이름 활용한 카멜 to 스네이크 변환)
  • catalog, schema 속성 : 카탈로그, 스키마 지정 가능
  • uniquConstraints 속성 : 유니크 제약 조건 생성 가능
@Table(
    name = "users",
    uniqueConstraints = {
        @UniqueConstraint(columnNames = "email"),
        @UniqueConstraint(columnNames = {"username", "phone"})
    }
)

위의 애노테이션 속성 설정처럼 "email"이라는 칼럼만 유니크 제약을 줄 수도 있고 "username" + "phone"에 대한 조합으로 유니크 제약을 줄 수도 있다.

hibernate.hbm2ddl.auto

// persistence.xml

<property name="hibernate.hbm2ddl.auto" value="create" />

위와 같이 persisence 설정 파일에서 사용할 수 있다.

  • create : 기존 테이블 drop 후 create

  • create-drop : 기존 테이블 drop 후 create 후 종료시점에 다시 drop

  • update : 변경만 반영

  • validate : 엔티티 - 테이블 정상 매핑 확인

  • none : 사용X

  • 운영 장비에는 절대 create, create-drop, update 사용하면 안됨. 테스트 서버에서 사용하는 것도 비추천. 개인 프로젝트나 개발 초기 단계에서만 잠깐 활용할 것.

Column Mapping

@Column

엔티티 클래스의 필드를 데이터베이스의 컬럼에 매핑하는 데 사용된다. 기본적으로 필드의 이름과 데이터 타입을 기반으로 매핑된다. 추가적으로 nullable, length 등의 속성을 설정할 수 있다.

  • name : 필드와 매핑할 테이블 컬럼 이름 설정(디폴트: 엔티티명 camel to snake 변환)
  • insertable = t/f : 등록 가능 여부
  • updatable = t/f : 변경 가능 여부
  • nullable : false시에 not null 조건 추가
  • unique : 유니크 제약 조건
  • columnDefinition : 생성 쿼리 직접 써서 넣을 수 있음.
  • length : 문자 길이 제약 조건
  • precision : 매우 큰 숫자나 정밀한 소수 사용할 때 범위 설정

@Temporal

날짜 타입을 매핑할 때 사용된다. java.util.Date나 java.util.Calendar와 같은 날짜 관련 타입에 적용된다. @Temporal은 TemporalType을 통해 날짜의 유형을 지정할 수 있다.

  • DATE: 날짜만 저장
  • TIME: 시간만 저장
  • TIMESTAMP: 날짜와 시간을 모두 저장

@Enumerated

enum 타입을 매핑하는 데 사용된다. 이 어노테이션을 사용하면 enum의 값을 데이터베이스의 문자열 또는 정수로 저장할 수 있다.
EnumType.ORDINAL: enum의 순서를 기반으로 저장
EnumType.STRING: enum의 이름을 기반으로 저장

  • **주의할 것은 속성으로 Enumtype.ORDINAL이 아닌 Enumtype.String을 사용해야 한다. 그 이유는 ORDINAL는 0,1,2 등 숫자로 대체되어 저장이 되는데, Enum의 구분가능한 내부 필드가 교체될 경우 순서에 따라 부여되므로 이전 순서와 다를 경우 DB에 저장은 되더라도 옳은 정보가 들어가진 않을 것이다.

@Lob

대용량 객체(BLOB, CLOB)를 매핑하는 데 사용된다. BLOB(Binary Large Object)와 CLOB(Character Large Object)로 구분되며, 이미지, 비디오 등의 큰 데이터나 긴 텍스트를 저장할 수 있다.

@Transient

특정 필드를 데이터베이스 컬럼에 매핑하지 않도록 지정한다. 이 어노테이션이 적용된 필드는 JPA에 의해 무시되며, 데이터베이스에 저장되지 않는다. 주로 계산된 값이나 임시 데이터를 저장하는 데 사용된다.

@Id

기본 키 매핑을 위해 ID에 해당하는 필드에 @Id 애노테이션을 부착한다. 이때 함께 잘 사용되는 애노테이션이 @GenerativeValue이다. 디폴트로 AUTO 속성을 가지는데 방언에 따라 나머지 세 가지를 자동 선택한다.

IDENTITY 전략

기본 키 값의 생성을 데이터베이스에 위임하는 방식이며 주로 MySQL에서 사용된다. 기본 키 필드는 데이터베이스에서 자동으로 증가하며, INSERT 문이 실행될 때마다 새로운 값을 생성한다.

persist()를 했는데 엔티티가 IDENTITY 전략일 경우, 기존의 아는 지식으로는 문제가 생긴다. IDENTITY 방식의 경우 엔티티의 ID를 null로 채워 보내면 DB에서 이를 보고 ID를 생성하는 것인데, persist()는 단순히 영속성 컨텍스트에 id가 없이 엔티티를 올려버려 이를 애플리케이션에서 활용할 수 없다는 문제가 발생한다.

JPA는 이를 해결하기 위해 IDENTITY전략의 엔티티의 경우 persist시 Insert쿼리를 즉각 실행해버린다.

SEQUENCE 전략

데이터베이스 시퀀스 오브젝트를 사용하여 기본 키 값을 생성하는 방식이다. 주로 Oracle과 같은 데이터베이스에서 사용된다. @SequenceGenerator 애노테이션을 사용하여 시퀀스의 이름과 초기 값을 정의할 수 있다.

@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;

시퀀스 전략도 동일하게 엔티티 생성 당시 시퀀스에서 ID 정보를 가져와야 하므로 IDENTITY 방식과 비슷한 문제가 발생한다. 이때 최적화 전략으로 allocationSize를 활용할 수 있다. 위의 코드처럼 설정하거나 설정을 하지 않을 경우 기본으로 50이 설정된다.

50개의 ID를 한 번에 메모리에 할당받고, 이 ID들을 영속성 컨텍스트에서 재사용한다. 이렇게 DB에 시퀀스에 자주 접근하지 않도록 최적화할 수 있어 IDENTITY 전략과 달리 persist()마다 DB에 접근하지 않아도 된다.

미리 할당된 ID(default=50개)를 사용하므로 여러 트랜잭션에서 동시에 ID를 생성해도 충돌이 발생하지 않는다.

동시성 문제에 있어 IDENTITY방식보다 시퀀스 방식은 독립적인 DB 객체이므로 더 안전하다는 장점이 존재한다.

하지만 시퀀스는 롤백시 ID낭비에 대한 우려가 존재하며 ID가 테이블에 같이 존재하는 것과 달리 모니터링등의 관리에 있어 어려움이 있을 수 있다.

TABLE 전략

기본 키 생성을 위한 전용 테이블을 사용하는 방식으로, 모든 데이터베이스에서 사용 가능하다. @TableGenerator 애노테이션을 사용하여 키 생성에 사용할 테이블의 이름과 컬럼을 지정할 수 있다. 이 방법은 DB에 의존하지 않고, 여러 데이터베이스에서 동일하게 동작한다.

  • TABLE 전략은 잘 사용하지 않는다. -> 많은 JOIN 필요, ID가 모두 모여있어 장애시 모든 엔티티에 영향을 미칠 수 있음. 동시성 개선에 대해 취약함.(LOCK을 걸면 모든 엔티티에 대해서 기다려야하니까)

AUTO 전략

데이터베이스 방언에 따라 자동으로 기본 키 생성 전략을 지정하는 방식, JPA 구현체가 적절한 전략을 선택하며, 기본값으로 설정된다.

권장하는 식별자(ID) 전략

ID가 가지는 중요한 3개의 특징은 not null, 유일성 보장, 불변이다.

이때 ID 구상에 있어 가장 까다롭게 작용하는 요소가 불변이다. 개발자가 쉽게 생각하여 주민등록번호 정도면 ID에 어울린다고 생각할 수 있겠지만 절대 변할 것 같지 않지만, 매우매우 낮은 확률로 변할 수 있는 실존 요소들이 많기 때문이다.

가장 권장되는 일반적인 형식은 다음과 같다.

  • Long형 + 대체키 + 키 생성전략을 사용하는 것이다. 대체키는 unique=true와 같은 값이다. 기본적으로 키 생성전략에 의한 Long형 Id를 사용하고 column에 unique=true와 같은 2차적인 키를 확보해놓는 것이다.
profile
자바집사의 거북이 수련법

0개의 댓글