[JPA] JPA Annotation, JPA Method

벼랑 끝 코딩·2025년 4월 14일

JPA

목록 보기
2/3

지난 포스팅에는 JPA를 사용하기 위한 기본 개념과
JPA에서 성능을 최적화하기 위한 핵심이 되는 요소들을 살펴봤다.

지난 포스팅에서 JPA를 사용하기 위해 기본적으로 알아두어야 했던 애노테이션 외에
다른 기본적인 애노테이션을 추가적으로 알아보자.


@Entity

@Entity
class Model {
	
    // ** 기본 생성자 필수 **
    public Model() {
    }
}

@Entity 애노테이션을 선언하면 JPA가 해당 클래스를 테이블로 자동 생성해준다.

@Entity가 선언된 클래스는 기본 생성자를 필수로 작성해야 한다.
final 클래스 및 enum, interface, 내부 클래스에는 선언할 수 없으며
@Entity 클래스 내부에 final 필드를 작성할 수 없다.

@Entity(name = "Entity Name")

name element를 사용하여 Entity 이름을 지정할 수 있다.
작성하지 않으면 기본값으로 클래스 이름이 Entity 이름으로 지정된다.
가급적 기본값을 사용한다.

@Table

@Table(name = "Table Name")
class ModelInfo {
	
    Stirng name;
    
    // 코드
}

@Table은 DB 테이블과 Entity를 매핑하는 애노테이션이다.

name element를 사용하여 연결할 Table 이름을 지정해서 사용할 수 있다.

// class : ModelInfo
논리 테이블명 : ModelInfo
DB 테이블명 : model_info

@Table 애노테이션을 선언하지 않는 경우 논리 테이블명은 클래스 이름 그대로,
DB 테이블명은 낙타 표기법에서 대문자를 소문자로 변경한 언더 스코어 표기법으로 변환한다.

테이블명 전략

// application.yml
spring:
  jpa:
    hibernate:
      naming:
      	//  ** 논리 이름 생성 전략 설정 **
        implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl
        //  ** 물리 이름 생성 전략 설정 **
        physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy

JPA는 테이블을 자동 생성하면서 Java 내부에서 사용하는 논리 이름과,
실제 테이블에 적용할 물리 이름을 생성한다.
application.yml(application.properties)에 테이블명 생성 전략을 선택할 수 있다.

DB 테이블명 생성 규칙이 다른 경우
SpringPhysicalNamingStrategy를 상속하여 커스터마이징할 수 있다.

@Id

@Id
Long id;

@Id는 DB 테이블의 primary Key(기본키)를 지정하는 애노테이션이다.

기본키는 null 값을 저장할 수 없고, 유일해야 하며 불변해야 한다.

오랫동안 변하지 않는 비즈니스 정보는 거의 없기 때문에,
기본키에 외에 무작위 값을 사용하는 대리키(대체키)를 사용하는 것이 권장된다.

@GeneratedValue, 기본키 전략

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;

primary Key키를 직접 할당하는 경우에는 @Id 애노테이션만 선언하면 된다.
하지만 직접 할당하는 것 외에도 기본키는 다양한 방식으로 생성할 수 있는데
기본키를 생성하는 방식을 기본키 전략이라고 하며,

@GeneratedValue 애노테이션의 strategy 속성을 사용하여 전략을 수립할 수 있다.

IDENTITY

IDENTITY 전략은 기본키 생성을 DB에 위임하는 전략이다.

자동 증가를 지원하는 DB에만 사용할 수 있다.

IDENTITY 전략은 DB에서 기본키를 생성하여 JPA 객체가 사전에 기본키를 알 수 없다.
따라서 객체를 조회하기 위해 entityManager의 persist() 메서드를 호출하는 시점에
INSERT SQL을 실행
하여 조회 시 기본키를 포함하여 데이터를 조회할 수 있다.

SEQUENCE

SEQUENCE 전략은 DB에서 고유 숫자 값을 생성해주는 SEQUENCE를 사용하는 전략이다.

generator 속성을 사용하여 식별자 생성기 이름을 입력하고
@SequenceGenerator의 name 속성에 작성한 식별자 생성기와 연결해야 한다.

@SequenceGenerator

SEQUENCE 전략을 사용하는 테이블 클래스에 @SequenceGenerator 애노테이션을 선언하고
애노테이션 속성을 작성하여 시퀀스를 설정해야 한다.
선언하지 않으면 JPA 기본 시퀀스인 hibernate_sequence를 사용한다.

  • name : 식별자 생성기 이름, @GeneratedValue의 generator 속성과 동기화
  • sequenceName : DB에 등록된 시퀀스 이름, 기본값 hibernate_sequence
  • initialValue : 초기값, DDL 자동 생성 시에만 적용, 기본값 1
  • allocationSize : 시퀀스 1회 호출 시 증가하는 숫자, 기본값 50

숫자가 순차적으로 증가해야 하는 경우 allocationSize를 1로 설정한다.
이 경우 기본키를 생성해야할 때마다
DB에서 시퀀스를 하나씩 호출해야 하므로 DB 접근을 위한 리소스가 소모된다.

allocationSize를 1이 아닌 다른 숫자로 설정 시 시퀀스 값을 미리 가져와 메모리에 저장하여
DB 접근을 위한 리소스를 절약하고 성능을 최적화할 수 있다.
하지만 먼저 시퀀스에서 값을 가져온 트랜잭션이 커밋하지 않은 상태에서
다른 트랜잭션이 시퀀스에서 값을 가져와 사용하는데
먼저 가져온 트랜잭션이 모든 시퀀스의 값을 사용하지 않는 경우,
전부 null 값으로 처리된다는 문제가 발생한다.

TABLE

TABLE 전략은 시퀀스를 테이블로 생성하여 사용하는 전략이다.

generator 속성을 사용하여 식별자 생성기 이름을 입력하고
@TableGenerator의 name 속성에 작성한 식별자 생성기와 연결해야 한다.

여러 시퀀스를 관리할 수 있다는 장점이 있다.

@TableGenerator

TABLE 전략을 사용하는 클래스에는 @TableGenerator 애노테이션을 선언하여
애노테이션 속성을 작성하여 시퀀스 테이블을 설정해야 한다.

  • name : 식별자 생성기 이름, @GeneratedValue의 generator 속성과 동기화
  • table : 시퀀스 테이블 이름, 기본값 hiberante_sequences
  • pkColumnName : 시퀀스 테이블에서 시퀀스 Column 이름
  • valueColumnName : 시퀀스 테이블에서 시퀀스의 값이 저장되는 Column 이름
  • pkVolumnValue : 시퀀스 테이블의 시퀀스 Column에 저장할 값
  • initialValue : 초기값, 기본값 0
  • allocationSize : 시퀀스 1회 호출 시 증가하는 숫자, 기본값 50

AUTO

AUTO 전략은 DB 종류에 따라 전략을 자동으로 생성하는 옵션이다.

전략을 명시하지 않고 @GeneratedValue 애노테이션만 선언하는 경우,
기본값인 AUTO 전략이 자동으로 선택된다.

@Column

@Column
String name;

@Column객체의 필드와 테이블의 컬럼을 매핑하는 애노테이션이다.

다양한 속성을 통해 Column 생성을 설정할 수 있다.

  • name : DB 컬럼의 이름과 다를 경우 연결할 Table 컬럼 이름 지정
  • insertable : 등록 가능 여부 설정
  • updatable : 변경 가능 여부 설정
  • nullable : null 허용 여부 설정, false의 경우 DDL 자동 생성 시 not null 추가
  • length : 문자 길이 제약 조건 설정, String에 사용
  • columnDefinition : 직접 Column DDL 작성
  • precision : 소수점 포함 전체 자릿수 설정, BigDecimal, BigInteger에만 사용
  • scale : 소수점 자릿수 설정, BigDecimal, BigInteger에만 사용

@Temporal

@Temporal(TemporalType.DATE)
Date date;

@Temporal객체의 날짜 타입 필드와 테이블의 컬럼을 매핑하는 애노테이션이다.

날짜는 TemporalType의 DATE 타입, 시간은 TIME, 날짜 + 시간은 DATETIME을 사용한다.
LocalDate, LocalDateTime 타입을 사용할 때에는 생략할 수 있다.

@Enumerated

@Enumerated(EnumType.STRING)
EnumClass enumClass;

enum EnumClass {
	SILVER, GOLD
}

@EnumeratedEnum 타입의 필드와 테이블의 컬럼을 매핑하는 애노테이션이다.

EnumType의 STRING 타입은 enum의 이름을 데이터베이스에 저장하는 방식이고,
ORDINAL 타입은 enum의 순서를 데이터베이스에 저장하는 방식이다.

ORDINAL 타입은 enum 필드가 추가될 경우 문제가 발생할 수 있기 때문에 사용을 금지한다.

EnumType은 STRING 타입을 사용해야 한다.

@Lob

@Lob  // CLOB
String longText;

@Lob  // BLOB
byte[] image;

@Lob은 객체의 BLOB, CLOB 타입의 필드와 테이블의 컬럼을 매핑하는 애노테이션이다.

Character Large OBject(CLOB)Binary Large OBject(BLOB) 데이터 타입에는
@Lob 애노테이션을 선언하여 매핑해야 한다.

@Transient

@Transient
String trasientField;

@Transient는 DB의 테이블과 매핑하지 않고 메모리에서만 관리하도록 선언하는 애노테이션이다.

DB 테이블과 매핑하지 않을 필드에 선언하여 사용한다.

@PrePersist, @PostPersist

@PrePersist  // ** DB 저장 전 호출 **
public void prePersist() {
	// 메서드 바디
}

@PostPersist  // ** DB 저장 후 호출 **
public void postPersist() {
	// 메서드 바디
}

@PrePersist, @PostPersist는 메서드에 선언 가능하며,
각각 persist() 메서드 호출 전, 후에 호출된다.

@PreUpdate, @PostUpdate와 같이 수정 전, 후에 호출되는 애노테이션과
@PreRemove, @PostRemove와 같이 삭제 전, 후에 호출되는 애노테이션도 사용할 수 있다.

피자를 먹을까 말까

마무리

JPA를 슬기롭게 사용하기 위해서는 우선 JPA 사용을 위해 선언해야 할
기본적인 애노테이션 부터 숙지해야 한다.
JPA 애노테이션에 대해 숙지하고 잘 사용해보자.

profile
복습에 대한 비판과 지적을 부탁드립니다

0개의 댓글