글을 쓰게 된 이유
프로젝트를 진행하면서 @Column(nullable = false)를 사용하다가 @NotNull은 왜 사용하지 않는걸까? 라는 생각을 했습니다.
@NotNull과 @Column(nullable = false)는 언뜻 보기에는 같은 기능을 하는 것처럼 보였습니다.
다만 차이가 있다면 DB layer에서 검증, 애플리케이션 layer에서 검증하는 차이라고 생각했지만 정확하게 어떤 차이가 있는지 알아보고자 다양한 테스트를 통해 확인해봤습니다.
dependency
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-validation'
runtimeOnly 'mysql:mysql-connector-java'
@NotNull을 사용하기 위해서는 validation 의존성을 추가해줘야합니다.
Entity, Test
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
@NotNull
private String username;
private int age;
}
@Test
void differenceBetweenNotNullAndNullable() throws Exception {
System.out.println("member 생성");
Member member = new Member(null, 10);
System.out.println("DB에 member 저장");
memberRepository.save(member);
}
ddl-auto : create + @NotNull
@NotNull은 javax.validation 패키지에 있고, Bean validation에 사용하는 annotation으로 Entity에만 사용되지 않습니다.
ddl query
ddl-auto를 이용하여 테이블을 생성할 때, username에 not null 제약 조건이 있는 것을 알 수 있습니다.
그렇다면 어떻게 DDL 쿼리에 not null 조건을 추가할 수 있을까요?
hibernate는 엔티티에 적용된 빈 유효성 검사 annotation을 DDL 스키마로 변환한다고 합니다.
만약 해당 기능을 사용하지 않고 싶다면 'hibernate.validator.apply_to_ddl' 속성을 false로 설정하면 됩니다.
age에는 null 조건을 명시하지 않았는데 왜 not null이 되있는걸까요?
@Column의 nullable의 default 값은 true이기 때문입니다.
만약 @Column을 이용하여 다른 조건을 주고 쿼리를 보겠습니다.
@Column(length = 55)
private int age;
not null 조건이 없어진 것을 알 수 있습니다.
not null 제약조건이 있는 column에 null 값을 넣을 경우
javax.validation.ConstraintViolationException이 발생했습니다. 즉, DB에 insert 쿼리를 보내기 전에 hibernate에서 유효성 검사를 트리거 했습니다.
ddl-auto : none + @NotNull
ddl-auto : create + @Column(nullable = false)
@Column은 javax.persistence에 포함되어있고, DDL 스키마를 생성하는데 사용됩니다.
당연히 DDL 스키마를 생성하는데 사용하므로 not null 제약조건이 들어가게 됩니다.
@NotNull과 다르게 java.sql에서 에러가 발생합니다. 또한, insert 쿼리가 나가고나서 에러가 발생하여 DB에서 예외를 트리거 한 것을 알 수 있습니다.
ddl-auto : none + @Column(nullable = false)
@Column은 DDL 스키마를 생성하는데 관여한다고 해서, 혹시 null을 확인하는 작업이 테이블을 생성할 때만 적용이 되는건가 싶어서 none을 이용하여 확인해보았습니다.
“Almost all the sources emphasize that @Column(nullable = false) is used only for schema DDL generation.”
하지만 DDL 쿼리가 나가든 안나가든 상관없이 유효성 검사를 하지 않고, DB에서 오류를 트리거 했습니다.
spring.jpa.properties.hibernate.check_nullability, @Column(nullable = false)
yml 파일에 위와 같은 옵션을 설정하면 hibernate가 insert 쿼리르 보내지 않고, 자체에서 오류를 트리거 했습니다.
즉, DB에 접근하지 않고 유효성 검사를 실시했습니다.
정리
처음에 생각한대로 @NotNull은 애플리케이션에서, @Column(nullable = false)는 DB layer에서 에러가 트리거 됐습니다.
하지만 yml 옵션을 통해서 @Column을 사용해도 애플리케이션 단에서 유효성 검사를 실시할 수 있습니다.
그렇다면 결국 옵션을 설정하지 않고 DB에 접근하는 리소스를 낭비하지 않기 위해서는 @NotNull을 사용하는 것이 좋지 않을까라는 생각을 하며 글을 마무리하겠습니다,,
ps. 현업에서는 ddl 쿼리를 hibernate에게 맡길 것 같지 않습니다,,?
REFERENCES
https://www.baeldung.com/hibernate-notnull-vs-nullable
'Spring Data' 카테고리의 다른 글
Spring Data JPA Optimistic lock, Pessimistic lock (0) | 2023.01.03 |
---|---|
Find vs Get (0) | 2022.09.25 |
JpaRepository vs CrudRepository (0) | 2022.08.23 |
Spring Data JPA에서의 벌크 삭제 정리 (0) | 2022.07.12 |
[YAPP] 검색 성능 최적화 일지(Feat. Elasticsearch) (0) | 2022.07.08 |