본문 바로가기

Spring 정리/Spring JPA

Entity

728x90
반응형

개요


 JPA를 사용하면, 기본은 엔티티(Entity)를 설정해 주는 것입니다. 일반 DB 테이블들을 어플리케이션 코드에서 매칭하기 위해서 설정합니다. 엔티티설정에는 필수적인 @Entity, @Id부터 유용한 설정들이 있습니다.

 

 

필수 값 지정


JPA로 DB를 사용하기 위해서 테이블이라는 의미로 엔티티를 지정해주어야 합니다.

- @Entity, @Id 2개가 필수값입니다.

 

 

 

  • @Id를 설정하는 방법

@Id는 보통 1씩 증가하는 Long 타입을 사용하여 유일성을 보장하도록 합니다.

이떄, @GeneratedValue를 사용하는데, entity PK를 설정하기 위한 키 생성 전략입니다. (default는 AUTO이다)

 

 

 

@Entity
@Data
@NoArgsConstructor
public class User {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    private String email;
}

 

@GeneratedValue뒤에 strategy를 설정하지 않으면 GenerationType.AUTO이 자동으로 설정됩니다.

 

 

@SpringBootTest
class UserRepositoryTest {
    @Autowired
    private UserRepository userRepository;

    @Test
    public void saveUser() {
        User user = new User();
        user.setEmail("mamamu9751");
        user.setName("paik");

        User savedUser = userRepository.save(user);

        User user2 = new User();
        user.setEmail("mamamu9751");
        user.setName("paik");

        User savedUser2 = userRepository.save(user2);
    }
}

 

 

  • GenerationType.IDENTITY

MYSQL에서 많이 사용, AUTO_INCREASE를 활용하여 ID를 증가시키며, 각 테이블마다 ID값을 개별적으로 사용합니다.

 

IDENTITY 테이블 생성과 저장

 

테이블에는 generated by default as identity로 각 테이블마다 1씩 증가합니다.
예시는 h2를 사용했는데, mysql을 사용한다면 id bigint not null auto_increment 로 나옵니다.

 

 

  • GenerationType.SEQUENCE

SEQUENCE 테이블 생성과 저장

 

 테이블에는 not null로만 들어갑니다. save()로 DB에 저장하기 이전에, call next value for hiberante_sequence 전략을 사용해서 1씩 증가시킵니다. 모든 테이블을 대상으로 1씩 증가합니다.

 

 

  • GenerationType.AUTO

각 DB에 맞게 적합한 방식으로 결정합니다. DB 의존성이 없다는 장점이 있습니다. 일반적으로는 직접 지정해서 사용합니다. (H2의 경우 AUTO는 SEQUENCE 방식을 따릅니다.)

 

 

  • GenerationType.TABLE

DB에 상관없이 별도의 테이블을 만들어서 관리합니다.

 

 

 

@Table에 name 사용하기


@Table로, 실제 DB에서 사용할 테이블 이름을 지정할 수 있습니다.

 

@Entity
@Data
@NoArgsConstructor
@Table(name = "legacy_user")
public class User {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    private String email;
}

 

클래스 User이지만, @Table로 legacy_user를 설정하면 테이블은 User가 아닌 legacy_user로 생성됩니다.

 

 

user가 아닌 legacy_user

 

 

  • 실제 운영에서는 어떤 설정까지 해야하나?
@Table(
name = "legacy_user", 
indexes = {@Index(columnList = "name")}, 
uniqueConstraints = {@UniqueConstraint(columnNames = {"email"})}
)

 

@Table 내부에 index 설정, uniqeConstraints설정 등을 할 수 있습니다.

 

 

 

 JPA로 테이블을 생성한다면 적용이 되지만, 만약 기존 DB 테이블이 존재할 경우, indexes와 uniqueConstraints는 동작하지 않습니다.  즉, 기존 DB 테이블에서 해당 설정이 되어 있으면 작동하지만 없다면 전혀 적용되지 않습니다. 운영에서 일반적으로 해당 사항은 DB 설정으로만 남기고 따로 @Table에서는 설정하지 않습니다.

 

 

@Column에 name, nullable 설정하기


DB 테이블과 Spring에서 사용하는 칼럼명이 다를 경우, @Column을 사용할 수 있습니다. DB 테이블에 저장되어 있는 칼럼을 @Column(name = "...")으로 지정하고 내가 Spring에서 사용하고 싶은 칼럼명을 정의하면 됩니다.

 

default가 null 허용이 true이기 때문에 꼭 값을 입력해야 한다면, @Column(nullable = false)로 설정하여, null이 입력되면 오류가 나도록 설정할 수 있습니다.

 

@Entity
@Data
@NoArgsConstructor
public class User {
    @Id
    @GeneratedValue
    private Long id;

    private String name;

    private String email;

    @Column(name="crtdat", nullable = false)
    private LocalDateTime createdAt;
}

 

createdAt -> crdat

 

org.springframework.dao.DataIntegrityViolationException: not-null property references a null 
or transient value : com.example.demo.domain.User.createdAt; nested exception is 
org.hibernate.PropertyValueException: not-null property references a null or transient value : 
com.example.demo.domain.User.createdAt

 

만약에, nullable = false인 칼럼이 null로 DB에 들어간다면, 다음과 같이 not-null 칼럼이 null을 참조한다는 예외가 나옵니다.

 

 

Enum 사용하기


Enum을 사용하려면 @Enumerated(EnumType.STRING)를 사용해야 합니다.

@Enumerated는 default가 @Enumerated(EnumType.ORIDNAL)인데, Enum 에 정의된 순서로 값을 구분한다는 의미입니다. 따라서, 만약에 중간에 데이터가 추가되었거나 순서가 바뀌면 데이터가 꼬이게 됩니다.

 

public Enum Gender {
 MALE,  //0
 FEMALE //1
}

순서 변경

public Enum Gender {
 FEMALE,  //0
 MALE     //1
}

중간에 데이터 추가

public Enum Gender {
 FEMALE,  //0
 MIX,     //1
 MALE     //2
}

 

기존에는 MALE이 0, FEMALE이 1이였지만, 순서를 바꾸면 FEMALE이 0, MALE이 1이 됩니다.

 

 

Listener를 이용하여 생성, 수정시간 생성하기


각 엔티티에 공통으로 필요한 생성시간, 수정시간, 작성자, 수정자를 공통 클래스로 처리할 수 있습니다. 

 

@EnableJpaAuditing
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

 

@EnableJpaAuditing을 통해 해당 프로젝트가 Audit 기능을 사용을 설정합니다.

 

@Getter
@MappedSuperclass
@EntityListeners(value = AuditingEntityListener.class)
public abstract class BaseEntity {
    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime updatedAt;
}

======================================================
public class User extends BaseEntity {

 

생성날짜, 수정날짜가 담긴 클래스를 생성하고 @CreatedDate@LastModifiedDate를 설정합니다.

 

@MappedSuperclass는 엔티티가 아니며, 상속받는 자식 클래스에 매핑 정보를 제공하는 역할을 합니다.

@Entity@Entity@MappedSuperclass로 정의된 클래스만 상속받을 수 있습니다.

 

@EntityListeners@Entity@MappedSuperclass가 설정된 클래스에 리스너를 추가해주는 어노테이션입니다.

 

 

 

정리


 JPA에서 Entity를 설정하는 방법들을 알아보았습니다. 각 프로젝트와 회사에 맞는 코딩 컨벤션이 있을 것으로 생각합니다. 특히, @EntityListeners를 통해 생성시간, 수정 시간을 간편하게 설정할 수 있는 것이 장점입니다. 운영에서는 어노테이션으로 설정을 잡는 것이 아니라, DB sql문에서 미리 설정하도록 합니다.

 

* 참고

한 번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지

 

728x90
반응형

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

N:1 테이블 관계 설계하기  (0) 2021.09.07
1:N 테이블 관계 설계하기  (0) 2021.09.07
1:1 테이블 관계 설계하기  (0) 2021.09.07
JPA 영속성 컨텍스트  (0) 2021.08.30
JPA  (0) 2021.08.28