자바생
article thumbnail
728x90

글을 쓰게 된 이유

프로젝트를 진행하면서 @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

 

 

 

 

 

728x90
profile

자바생

@자바생

틀린 부분이 있다면 댓글 부탁드립니다~😀

검색 태그