2022/03/07 Entity 기본속성살펴보기

김석진·2022년 3월 7일
0

BookManager

목록 보기
3/3

Entity의 기본속성(annotation)

@Entity

@Entity는 JPA가 관리하는 Entity임을 명시함

@ID

@Entity로 명시한 객체는 반드시 PK(Primary Key)가 존재함
이를 @ID로 애노테이션으로 PK를 지정함

@GeneratedValue


GenerationType은 4가지를 제공하는데 TABLE,SEQUENCE,IDENTITY,AUTO 가있다

IDENTITY

일반적으로 MYSQL에서 사용하는 전략, 상용적인 서비스는 MYSQL이나 MariaDB를 사용하는데 이때 많이 사용함

SEQUENCE

ORACLE 등에 많이 사용함, H2 DB도 SEQUENCE 를 사용함

TABLE

DB의 종류에 상관없이 ID값을 관리하는 별도의 TABLE을 만들고 그 TABLE에서 ID값을 추출해서 사용할 수 있도록 제공

AUTO

일반적인 Default 값
각 DB에 적합한 값을 제공해줌

@Table


일반적으로 name을 자동으로 설정해줌 특별한 경우 name,schema,catalog를 설정할 경우가 있다

UniqueConstraint:제약조건과 Index:index를 세팅할 수 있다.
주의할점 Index와 UniqueConstraint는 실제 DB에 세팅된것과 다르게 적용 될 수 있다.

@Column

유저필드에 각 컬럼의 속성을 지정하는 필드영역의 애노테이션이다 .

@Target({METHOD, FIELD}) 
@Retention(RUNTIME)
public @interface Column {

    /**
     * (Optional) The name of the column. Defaults to 
     * the property or field name.
     */
    String name() default "";

    /**
     * (Optional) Whether the column is a unique key.  This is a 
     * shortcut for the <code>UniqueConstraint</code> annotation at the table 
     * level and is useful for when the unique key constraint 
     * corresponds to only a single column. This constraint applies 
     * in addition to any constraint entailed by primary key mapping and 
     * to constraints specified at the table level.
     */
    boolean unique() default false;

    /**
     * (Optional) Whether the database column is nullable.
     */
    boolean nullable() default true;

    /**
     * (Optional) Whether the column is included in SQL INSERT 
     * statements generated by the persistence provider.
     */
    boolean insertable() default true;

    /**
     * (Optional) Whether the column is included in SQL UPDATE 
     * statements generated by the persistence provider.
     */
    boolean updatable() default true;

    /**
     * (Optional) The SQL fragment that is used when 
     * generating the DDL for the column.
     * <p> Defaults to the generated SQL to create a
     * column of the inferred type.
     */
    String columnDefinition() default "";

    /**
     * (Optional) The name of the table that contains the column. 
     * If absent the column is assumed to be in the primary table.
     */
    String table() default "";

    /**
     * (Optional) The column length. (Applies only if a
     * string-valued column is used.)
     */
    int length() default 255;

    /**
     * (Optional) The precision for a decimal (exact numeric) 
     * column. (Applies only if a decimal column is used.)
     * Value must be set by developer if used when generating 
     * the DDL for the column.
     */
    int precision() default 0;

    /**
     * (Optional) The scale for a decimal (exact numeric) column. 
     * (Applies only if a decimal column is used.)
     */
    int scale() default 0;

Insert/Update시 @Column에노테이션의 기능을 이용하여 Insert/Update될 값을 지정할 수 있다.

  @Column(updatable = false)
    private LocalDateTime createdAt;
  // 업데이트시 데이터 변경 X  
    
    @Column(insertable = false)
    private LocalDateTime updatedAt;
    
  // 인서트시 데이터 변경 X

@Transient

라는 어노테이션이 붙어잇는 필드는 영속성 처리에 제외 DB 데이터에 반영되지 않고 해당 객체와 생명주기를 함께하는 필드가 된다.

ENUM에 대한 처리

ENUM은 자바에서 사용하는 일종의 상수 객체
ENTITY에는 별도의 처리방법을 가짐

JPA에서 ENUM을 어떻게 다루는지에 대해서 알아보자

public enum Gender {
    MALE,
    FEMALE
}
    @Enumerated(value = EnumType.STRING)
    private Gender gender;

이렇게 @Enumerated라는 애노테이션을 이용하여 JPA에서는 ENUM을 다룬다.

Hibernate: 
    select
        user0_.id as id1_1_,
        user0_.created_at as created_2_1_,
        user0_.email as email3_1_,
        user0_.gender as gender4_1_,
        user0_.name as name5_1_,
        user0_.updated_at as updated_6_1_ 
    from
        user user0_
User(id=1, name=kim, email=kimseokjin0324@gmail.com, gender=MALE, createdAt=2022-03-07T01:07:02.071242, updatedAt=2022-03-07T01:07:02.071242)
User(id=2, name=lee, email=lee@gmail.com, gender=null, createdAt=2022-03-07T01:07:02.086247, updatedAt=2022-03-07T01:07:02.086247)
User(id=3, name=hong, email=hong@gmail.com, gender=null, createdAt=2022-03-07T01:07:02.090247, updatedAt=2022-03-07T01:07:02.090247)
User(id=4, name=park, email=park@gmail.com, gender=null, createdAt=2022-03-07T01:07:02.091247, updatedAt=2022-03-07T01:07:02.091247)
User(id=5, name=park, email=park2@gmail.com, gender=null, createdAt=2022-03-07T01:07:02.091247, updatedAt=2022-03-07T01:07:02.091247)
Hibernate: 
    select
        * 
    from
        user limit 1;
MALE

제대로 출력됨을 알 수 있다.

Entity Listenr의 활용

    @PrePersist     //인서트 메서드가 호출되기 전에 실행되는 메소드
    @PreUpdate      //merge 메소드가 호출되기전
    @PreRemove      //Delete 메소드가 호출되기전
    @PostPersist    //인서트 메서드가 호출된 후에 실행되는 메소드
    @PostUpdate
    @PostRemove
    @PostLoad       // select조회가 일어난 직후에 실행되는 메소드

호출되는 시점을 로그를 통해 알아보자

>>>> prePersist
Hibernate: 
    call next value for hibernate_sequence
Hibernate: 
    insert 
    into
        user
        (created_at, email, gender, name, updated_at, id) 
    values
        (?, ?, ?, ?, ?, ?)
>>>> postPersist
Hibernate: 
    select
        user0_.id as id1_1_0_,
        user0_.created_at as created_2_1_0_,
        user0_.email as email3_1_0_,
        user0_.gender as gender4_1_0_,
        user0_.name as name5_1_0_,
        user0_.updated_at as updated_6_1_0_ 
    from
        user user0_ 
    where
        user0_.id=?
>>> postLoad
Hibernate: 
    select
        user0_.id as id1_1_0_,
        user0_.created_at as created_2_1_0_,
        user0_.email as email3_1_0_,
        user0_.gender as gender4_1_0_,
        user0_.name as name5_1_0_,
        user0_.updated_at as updated_6_1_0_ 
    from
        user user0_ 
    where
        user0_.id=?
>>> postLoad
>>>> preUpdate
Hibernate: 
    update
        user 
    set
        email=?,
        gender=?,
        name=?,
        updated_at=? 
    where
        id=?
>>>> postUpdate
Hibernate: 
    select
        user0_.id as id1_1_0_,
        user0_.created_at as created_2_1_0_,
        user0_.email as email3_1_0_,
        user0_.gender as gender4_1_0_,
        user0_.name as name5_1_0_,
        user0_.updated_at as updated_6_1_0_ 
    from
        user user0_ 
    where
        user0_.id=?
>>> postLoad
>>>> preRemove
Hibernate: 
    delete 
    from
        user 
    where
        id=?
>>>> postRemove
인서트가 호출 전 prePersist, 쿼리완료 후 postPersist
select 후 postLoad가 발생하고 update 쿼리 전 preUpdate, 쿼리 완료후 postUpdate , Delete동작전 preRemove, 쿼리 완료 후 postRemove 가 동작함을 알 수 있다

언제 사용되는지?

현업에서 가장 많이 사용하는 어노테이션은 @prePersist, @preUpdate이라고 하셨다.
User 객체에서 createdAt, updatedAt이라는 필드가 있는데 개발자가 실수를 하여 여기에 값을 주입하지않는다면 빈값이 들어가는 오류가 발생할 수도 있다
insert시 이 필드에 값을 넣고싶을때 @prePersist를 사용한다

  @PrePersist     //인서트 메서드가 호출되기 전에 실행되는 메소드
    public void prePersist() {
        this.createdAt = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
    }

    @Test
    void prePersistTest() {
        User user = new User();
        user.setEmail("kimseokjin03@gamil.com");
        user.setName("kimseok");

        userRepository.save(user);

        System.out.println(userRepository.findByEmail("kimseokjin03@gamil.com"));
    }

테스트를 진행하면 우리가 setCreatedAt, setUpdatedAt을 통해 현재시간을 세팅하지 않아도

User(id=6, name=kimseok, email=kimseokjin03@gamil.com, gender=null, createdAt=2022-03-07T13:25:35.615963, updatedAt=2022-03-07T13:25:35.615963)

현재시간이 잘 들어간것을 확인 할 수 있다

@preUpdate는 위와 동일하게 업데이트 시간만 변경을 원할때 즉 Update쿼리가 동작할때 리스너를 사용하면 될 것같다.

히스토리 데이터의 경우 해당 데이터가 수정이 될 경우 해당 데이터 복사본을 다른 테이블에 저장해두는 경우가 있다.

profile
주니어 개발자 되고싶어요

0개의 댓글