@Entity는 JPA가 관리하는 Entity임을 명시함
@Entity로 명시한 객체는 반드시 PK(Primary Key)가 존재함
이를 @ID로 애노테이션으로 PK를 지정함
GenerationType은 4가지를 제공하는데 TABLE,SEQUENCE,IDENTITY,AUTO 가있다
일반적으로 MYSQL에서 사용하는 전략, 상용적인 서비스는 MYSQL이나 MariaDB를 사용하는데 이때 많이 사용함
ORACLE 등에 많이 사용함, H2 DB도 SEQUENCE 를 사용함
DB의 종류에 상관없이 ID값을 관리하는 별도의 TABLE을 만들고 그 TABLE에서 ID값을 추출해서 사용할 수 있도록 제공
일반적인 Default 값
각 DB에 적합한 값을 제공해줌
일반적으로 name을 자동으로 설정해줌 특별한 경우 name,schema,catalog를 설정할 경우가 있다
UniqueConstraint:제약조건과 Index:index를 세팅할 수 있다.
주의할점 Index와 UniqueConstraint는 실제 DB에 세팅된것과 다르게 적용 될 수 있다.
유저필드에 각 컬럼의 속성을 지정하는 필드영역의 애노테이션이다 .
@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;
@Column(updatable = false)
private LocalDateTime createdAt;
// 업데이트시 데이터 변경 X
@Column(insertable = false)
private LocalDateTime updatedAt;
// 인서트시 데이터 변경 X
라는 어노테이션이 붙어잇는 필드는 영속성 처리에 제외 DB 데이터에 반영되지 않고 해당 객체와 생명주기를 함께하는 필드가 된다.
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
제대로 출력됨을 알 수 있다.
@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쿼리가 동작할때 리스너를 사용하면 될 것같다.
히스토리 데이터의 경우 해당 데이터가 수정이 될 경우 해당 데이터 복사본을 다른 테이블에 저장해두는 경우가 있다.