본문 바로가기
ORM/Spring Data JPA

Entity 개념 & 기본 사용법

by 코딩하는 랄로 2024. 1. 11.
728x90

@Entity

ORM(Object-Relational Mapping)은 자바의 객체와 데이터베이스의 데이터를 Mapping 해주는 개념이다. 비영속성인 자바의 객체를 ORM을 통해 DB에 자동으로 매핑을 해주어 영속화시켜줌으로써, 자바의 객체만으로도 데이터 베이스의 데이터를 다룰 수 있게 되는 것이다.

 

이 때에, DB와 Mapping이 되는 자바 객체를 Entity라고 한다. JPA는 이러한 Entity를 이용하여 Table을 생성하기 때문에 자바 객체가 Entity임을 알려주어야 하는데, 그를 위한 annotation이 @Entity이다.

@Data
@NoArgsConstructor
@Entity
public class Student {

}

 

위와 같이 자바의 클래스 위에 @Entity를 붙여주면 해당 클래스 이름을 테이블 이름으로 가지는 테이블이 생성이 된다. (생성되는 테이블의 이름을 변경하고 싶다면 @Entity의 name 속성으로 변경 가능 ) 테이블이 생성이 되는지 확인하기 위해 Spring 서버를 동작시키면 에러가 발생한다. 왜냐하면 Entity로 지정된 클래스가 PK 를 가지고 있지 않기 때문이다!!

 

 

@Id

JPA에서 일반 객체 데이터와 영속성 객체 데이터를 구분하는 방법은 바로 PK(primary key) 값의 유무이다. 해당 PK 값이 null 인지 아닌지를 통해 같은 Entity로 지정된 클래스로 생성된 객체라도 영속성인지 아닌지를 알 수 있는 것이다. 그렇기 때문에 Entity로 지정된 객체는 필수로 PK 값을 가져야 한다.

 

이를 위해 사용하는 Annotation이 @Id 이다.

@Data
@NoArgsConstructor
@Entity
public class Student {
    @Id  // Primary Key
    private Long id;
}

 

이제 Server를 돌리면, Hibernate가 Entity 객체를 이용하여 테이블을 생성할 것인데, 이를 위해서는 사전에 설정 작업이 추가 되어야 한다. spring project의 application.yml(or properties) 에 다음의 설정을 추가해주자.

>>> .properties
# JPA 를 통해 생성되는 SQL 문을 콘솔 출력
spring.jpa.show-sql=true
# Query 가 가독성 좋게 포매팅 되어 로그 찍힌다.
spring.jpa.properties.hibernate.format_sql=true
# Spring Server 동작시, 기존의 table은 삭제 후 다시 생성
spring.jpa.hibernate.ddl-auto=create

>>> .yml
spring:
  jpa:
    show-sql: true 
    properties:
      hibernate.format_sql: true 
    hibernate: ddl-auto: create

 

위의 두 설정은 JPA를 통해 생성되는 SQL문을 출력하고 이를 가독성 좋게 보기 위한 설정이다. 마지막 설정이 JPA가 서버 가동시에 ddl을 생성을 위한 설정이다. 옵션으로는 아래와 같다.

  • create : 기존의 테이블을 삭제하고 새로 생성
  • create-drop : create 속성이 서버가 실행될 때, 기존의 테이블을 삭제한다면 이 옵션은 서버가 종료될 때 테이블 삭제
  • update : 기존 테이블의 변경 사항만 적용
  • none : 자동 생성 기능을 사용하지 않음
  • validate : 기존 테이블의 변경 사항이 생기면 경고를 띄우고 서버를 중단. DDL을 수행하지 않음

옵션은 상황마다 바꾸어 가면서 사용하면 좋다. 기본적으로 개발 초기에 ERD 설계를 할 때에는 creat 또는 create-drop을 사용하면 좋고 이 후에는 update를 통해 개발을 진행하면 된다.

 

 

@GeneratedValue

서버를 가동하여 생성되는 DDL을 확인하기 전에 PK 값을 하나만 더 설정해주도록 하자. Student 클래스의 PK인 id 를 Auto Increment 로 지정하여 주겠다. 이를 위해서는 @GeneratedValue annotation을 사용한다.

@Data
@NoArgsConstructor
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
}

 

@GeneratedValue의 strategy의 타입 또한 여러가지가 존재한다. 이러한 타입은 자신이 사용하는 DB에 맞춰서 설정해주면 된다.

  • IDENTITY : 기본 키 생성을 DB에 위임(= AUTO_INCREMENT) ex. MySQL 
  • SEQUENCE :  데이터베이스 시퀀스를 사용해서 기본키를 할당, 데이터베이스 시퀀스에서 식별자 값을 획득한 후 영속성 컨텍스트에 저장, 유일한 값을 순서대로 생성 ex. Oracle, PostgreSQL, DB2, H2
  • TABLE : 키 생성 테이블을 사용, 키 생성 전용 테이블 하나를 만들고 여기에 이름과 값으로 사용할 컬럼을 만들어 데티어베이스 시퀀스를 흉내내는 전략. 모든 데이터베이스에서 사용가능
  • AUTO : 선택한 데이터베이스에 따라 방식을 자동으로 선택, strategy 타입을 지정해주지 않는 경우 auto 타입이 default로 지정된다.
  • UUID : Universally Unique Identifier를 사용하여 키본키를 생성

이제 서버를 가동해서 출력되는 DDL을 확인해보면 다음의 결과를 볼 수 있다.

Hibernate:
drop table if exists Student
Hibernate:
  create table Student (
    id bigint not null auto_increment,
    primary key (id)
  ) engine=InnoDB

 

 

@Column

테이블의 다른 컬럼을 추가하기 위해서는 Entity 객체에 그냥 선언만 해주어도 해당 이름을 가지 컬럼이 생성이 된다!!

@Data
@NoArgsConstructor
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String address;

    private int mathScore;
    private Integer engScore;
}

 

서버를 가동시켜 생성되는 DDL을 확인해보면 아래와 같이 property 이름으로 컬럼이 잘 생성되는 것을 확인할 수 있다.

Hibernate: 
    drop table if exists Student
Hibernate: 
    create table Student (
        engScore integer,
        mathScore integer not null,
        id bigint not null auto_increment,
        address varchar(255),
        name varchar(255),
        primary key (id)
    ) engine=InnoDB

 

이 때 주의 깊게 봐야 할 것은 바로 mathScore 와 engScore 컬럼이다. JPA는 Entity 객체의 property가 primitive type인 경우에는 not null 조건을 추가하고 아닐 경우 null 을 허용하도록 한다.

 

이렇게 단순히 property를 추가함으로써 컬럼을 생성할 수 도 있지만, primitive type이 아니지만 null을 허용하고 싶지 않을 경우 또는 다른 이름으로 컬럼값으로 지정하고 싶거나 해당 컬럼에 unique 속성을 추가하고 싶을 때는 해당 방법으로는 불가능하다.

 

이럴 때에 사용하는 annotation이 @Column 이고 가지고 있는 속성으로는 다음과 같다. ( 몇가지 자주 사용되는 속성들!!)

  • name : 생성되는(매핑되는) 테이블의 컬럼 이름을 지정해줄 수 있다.
  • nullable : null 값의 허용 여부를 설정한다. false = not null
  • unique : unique 제약 조건을 걸 수 있다.
  • columnDefinition : 데이터베이스의 default 값, 속성 타입 등 컬럼 정보를 직접 줄 수 있다. 
  • length : String 타입의 property에만 사용가능하고 문자의 길이를 지정해 줄 수 있다. 기본값은 255이다.

각각의 속성을 이용하여 생성되는 DDL을 확인해보자.

@Data
@NoArgsConstructor
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "student_name",nullable = false)
    private String name;

    @Column(nullable = false, length = 500)
    private String address;

    @Column(unique = true, nullable = false)
    private int mathScore;

    @Column(columnDefinition = "integer default 50")
    private Integer engScore;
}

 

아래와 같이 DDL이 잘 생성된 것을 볼 수 있다.

Hibernate: 
    create table Student (
        engScore integer default 50,
        mathScore integer not null,
        id bigint not null auto_increment,
        address varchar(500) not null,
        student_name varchar(255) not null,
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    alter table Student 
       add constraint UK_b30d0iu7b70yx4f98brr2gaas unique (mathScore)

 

@Column의 nullable 속성의 default 값은 true이기 때문에 해당 annotation을 primitive type에 달아주게 되면 not null 제약조건이 사라지기 때문에 꼭 nullable 속성 값을 false로 바꿔줘야 한다!!

 

 

@Table

@Column과 마찬가지로 @Entity에서 지정해주지 못하는 여러 가지 설정들을 @Table을 통해서 지정해 줄 수 있다. 여러 속성 중 자주 사용되는 속성을 살펴보자.

  • name : @Entity의 name 속성과 마찬가지로 테이블의 이름을 지정해준다.
  • indexes : 컬럼에 대한 index를 생성한다.
  • uniqueConstraints : unique 제약조건을 걸 컬럼을 지정할 수 있다.

각 속성을 사용한 @Table annotation을 다음과 같이 달아주었다.

@Data
@NoArgsConstructor
@Entity
@Table(
        name = "ex_student",
        indexes = {@Index(columnList = "student_name")},
        uniqueConstraints = {@UniqueConstraint(columnNames = {"mathScore", "student_name"})}
)
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "student_name",nullable = false)
    private String name;

    @Column(nullable = false, length = 500)
    private String address;

    private int mathScore;

    @Column(nullable = false)
    private Integer engScore;
}

 

name property의 테이블에서의 컬럼명을 student_name으로 변경해주기 때문에 @Table 의 속성에서 지정해줄 때에도 name으로 지정해준 컬럼명을 사용하여야 한다. 생성되는 DDL을 다음과 같다.

Hibernate: 
    create table ex_student (
        engScore integer not null,
        mathScore integer not null,
        id bigint not null auto_increment,
        address varchar(500) not null,
        student_name varchar(255) not null,
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    create index IDXk3y5ygkh83ul5lgisso7so5ko 
       on ex_student (student_name)
Hibernate: 
    alter table ex_student 
       add constraint UKkdi89xypgb5d8vyu5d26rd92i unique (mathScore, student_name)

 

table 명이 지정된 이름으로 생성되었고 indexing과 unique 제약 조건도 잘 거는 것을 볼 수 있다.

 

 

@Transient

만약 Entitiy 객체에서 특정 property를 테이블 생성 시에 제외하고 싶다면 어떻게 할까? 이 때에 사용하는 annotation이 @Transient 이다.

@Data
@NoArgsConstructor
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private String address;

    @Transient
    private int mathScore;
    private Integer engScore;
}

 

mathScore 에 해당 annotation을 걸어주었고, 정말 제외되는지 DDL을 확인해보자.

Hibernate: 
    create table Student (
        engScore integer,
        id bigint not null auto_increment,
        address varchar(255),
        name varchar(255),
        primary key (id)
    ) engine=InnoDB

 

mathScore 는 제외시키고 Student 테이블을 생성하는 것을 볼 수 있다. @Transient annotation은 객체의 임시로 값을 저장하기 위한 property를 선언해줄 때 유용한 annotation이다.

 

 

728x90

'ORM > Spring Data JPA' 카테고리의 다른 글

기본 CRUD - Create & Update  (0) 2024.01.16
기본 CRUD - DELETE  (1) 2024.01.16
기본 CRUD - READ  (0) 2024.01.16
JPA Repository - 개념  (0) 2024.01.15
JPA 란  (1) 2024.01.05