JPA

[JPA] 엔티티 매핑 / 데이터베이스 스키마 자동 생성 기능 (ddl-auto)

syj0522 2024. 9. 11. 17:27

JPA는 엔티티 객체와 DB 테이블을 연결해서 개발자가 직접 쿼리를 쓰지 않고 메서드로 간단하게 데이터베이스에 접근할 수 있게 해줍니다. 그런데 어떤 엔티티 객체와 DB 테이블이 대응되는지는 개발자가 직접 어노테이션을 붙여서 JPA에게 알려줘야 합니다.

 

이번 포스팅에서는 JPA에서 엔티티를 매핑할 때 자주 쓰이는 어노테이션에 대해 알아보겠습니다.

 


@Entity
@Table(name="MEMBER")
public class Member {
    ...

@Entity

  • 테이블과 매칭될 클래스
  • 실제로 DB 테이블과 연결되기 때문에, 내용이 DB 테이블과 다르면 안 됨.
  • name : jpa에서 사용할 엔티티 이름 지정. 디폴트값은 클래스 이름인데, 보통 클래스 이름을 사용함. 다른 패키지에 이름이 같은 엔티티 클래스가 있다면 이름을 지정해서 충돌하지 않도록 해야 함.
  • 기본 생성자(파라미터 없는 public 또는 protected 생성자) 필수
    • @NoArgsConstructor은 파라미터 없는 기본 생성자를 자동으로 생성해주는 어노테이션이므로 @Entity와 자주 같이 쓰인다.
    • 자바는 생성자를 하나 이상 만들면 기본 생성자를 자동으로 만들어놓지 않기 때문에 주의해야 함
  • final, enum, interface, inner 클래스에는 사용 불가
  • 저장할 필드에 final 사용 불가

 

@Entity는 public, protected인 기본 생성자(파라미터 없는 생성자)가 필수입니다. 자바는 생성자가 하나도 없으면 기본 생성자를 만들지만 하나 이상의 생성자를 직접 만든다면 기본 생성자가 만들어지지 않기 때문에, 생성자가 여러 개일 때는 기본 생성자가 있는지 확인해야 합니다. (이 문제가 생기는 것을 방지하기 위해 @NoArgsConstructor가 쓰입니다.)

 

엔티티의 모든 필드들은 final을 사용할 수 없습니다. 이는 지연로딩과 관련이 있는데, JPA는 DB에서 데이터를 조회한 후 엔티티를 생성할 때 '지연로딩'전략을 사용합니다. 지연로딩을 이용해 DB를 조회하기 위해서는 JPA 프록시 객체를 생성해야 합니다. final field가 포함된 클래스는 상속될 수 없는 특징을 가지고 있기 때문에(실행 시, 메모리 최상단에 위치) 해당 클래스를 확장하여 프록시 객체로 사용할 수 없습니다.

 

@NoArgsConstructor

파라미터가 없는 기본 생성자를 자동으로 생성해주는 어노테이션입니다. 앞에서 얘기했듯이 기본 생성자가 필수기 때문에 @Entity는 보통 @NoArgsConstructor와 함께 쓰입니다. @NoArgsConstructor(access = AccessLevel.PROTECTED)로 엔티티에 외부 접근이 오는 것을 막을 수 있습니다.

 

 

@Table

  • 엔티티와 매핑할 테이블
  • name : 매핑할 테이블 이름. name속성을 지정해주지 않으면 엔티티 클래스 이름을 테이블명으로 지정.

 

 

데이터베이스 스키마 자동 생성 기능(ddl-auto)

 

JPA는 데이터베이스 스키마를 자동으로 생성해주는 기능이 있습니다. application.properties에 아래와 같은 속성을 추가하면 jpa가 애플리케이션 실행 시점에 데이터베이스 테이블을 자동으로 생성합니다.

jpa:
    hibernate:
        ddl-auto: update

(프레임워크 없는 maven project에는 persistence.xml에 아래처럼 추가합니다.)

<persistence>
    <properties>
            <property name="hibernate.hbm2ddl.auto" value="update" />

 

속성 설명
create 기존 테이블 삭제하고 새로 생성 (drop + create)
create-drop create 속성 + 애플리케이션 종료할 때 생성한 DDL을 제거 (drop + create + drop)
update 데이터베이스 테이블과 엔티티 매핑 정보를 비교하여 변경사항 수정
validate 데이터베이스 테이블과 엔티티 매핑 정보를 비교하여 차이가 있으면 경고, 애플리케이션을 실행하지 않음 (DDL수정x)
none 자동 생성 기능을 사용하지 않음 (또는 ddl-auto 옵션을 작성하지 않아도 됨)

 

📍주의 

실행 결과를 보며 매핑 결과가 어떻게 되는지 공부할 때는 유용하게 활용할 수 있지만, 실제로 운영하는 서비스에서는 이 옵션(create, update)을 사용해서 DDL을 수행하게 하면 절대 안 됩니다. 이 옵션에 의해 운영 중인 데이터베이스의 테이블이나 컬럼이 삭제될 수 있기 때문입니다.

 

📍추천 설정 

  • 개발 초기 단계 : create 또는 update
  • 초기화된 상태로 자동화 테스트를 진행하는 개발자 환경 : create 또는 create-drop
  • 테스트 서버 : update 또는 validate
  • 스테이징과 운영 서버 : validate 또는 none

 

DDL 자동 생성 시 쓰이는 속성들

이 속성들은 hibernate.hbm2ddl.auto 설정으로 DDL 자동 생성을 켜놓아야 기능을 하는 속성들입니다. 그래서 DDL 자동 생성 시에만 사용되고 JPA 실행 로직에는 영향을 주지 않습니다. DDL을 직접 만든다면 필요 없는 속성들입니다.

 

하지만 나중에 개발하면서 엔티티의 제약 조건을 참고할 때 유용하기 때문에 ddl-auto를 안 쓰더라도 명시해두면 좋습니다.

 

@Column의 nullable, length속성

@Column(name = "NAME", nullable = false, length = 10)
private String name;
 
  • nullable : 테이블을 생성할 때 컬럼에 not null 속성을 추가함
  • length : 테이블을 생성할 때 컬럼 타입에 길이를 지정함
//생성되는 DDL
create table MEMBER (
    NAME VARCHAR(10) not null, 
...
)
 

@Unique

@Table(name = "MEMBER", uniqueConstraints = {@UniqueConstraint(
    name = "NAME_AGE_UNIQUE",
    columnNames = ("NAME", "AGE") )})
 

컬럼에 유니크 속성을 주면 그 컬럼의 데이터는 모두 고유한 값을 가져야 합니다.

NULL값도 허용됩니다. (NULL은 데이터 중복으로 취급하지 않음)

 

create할 때 유니크 속성을 지정하는 방법은 두 가지입니다. 두 번째 방법을 사용하면 제약조건에 이름을 설정할 수 있습니다.

//생성되는 DDL
create table 테이블이름 (
    필드명 필드타입 UNIQUE,
...
)
create table 테이블이름 (
    필드명 필드타입, 
...
    CONSTRAINT 제약조건 이름 UNIQUE (필드이름)