일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Kenneth Park
- California State University Sacramento
- i-20
- 사이드프로젝트
- 자바 스터디
- java
- Java 스터디
- 만다라트프로젝트
- 미국유학생활
- jpa
- 개발일지
- 미국유학
- 부산외대
- F1학생비자
- 복수학위제도
- 비전공자 git
- CSUS
- 파이데이아창의인재학과
- JVM아키텍처
- 케네스
- 미국대학생활
- 자바
- 해외유학
- 2+2
- 유학생 준비물
- 개인 프로젝트 개발일지
- 케네스로그
- 미국유학생
- 미국대학
- 유학생대학생활
- Today
- Total
케네스로그
엔티티 Null체크, @Column과 @NonNull 어떤걸 써야할까? 본문
엔티티를 정의하면서 궁금했었고, SpringDeepDive 스터디에서 나왔던 질문이었다.
@Column(nullable=false)와 @NotNull 두가지의 null 방지 어노테이션을 사용할 수 있다.
과연 실제 코드에서는 어떤 차이를 보일까?
@Column과 @NonNull
jakarta.persistence의 @Column(nullable=false)의 설명은 다음과 같다.
Specifies the mapped column for a persistent property or field. If no Column annotation is specified, the default values apply. Whether the database column is nullable.
lombok의 @NotNull의 설명은 다음과 같다.
If put on a parameter, lombok will insert a null-check at the start of the method / constructor’s body, throwing a NullPointerException with the parameter’s name as message. If put on a field, any generated method assigning a value to this field will also produce these null-checks.
설명으로 유추해봤을 땐, @Column은 데이터베이스에 엔티티를 저장할 때, 필드가 null인지 여부를 확인하여 Exception을 발생시킨다.
반면, @NonNull은 메소드나 생성자 수준에서 필드에 대한 null 체크를 하여 NPE를 발생시킨다.
질문에 대한 내 답은 '@NonNull을 사용하는 것이 좋다'였다.
그 이유는, Repository Layer에서 데이터베이스를 접근하기 전에 생성자를 사용하는 Service Layer에서 널체크를 진행할 수 있기때문이다. 다른 레이어로 이동하기 전에 예외를 잡아낼 수 있는 것이 당연히 더 효율적일거라 생각했다.
코드로 직접 확인해보자
간단한 예제로 Member entity, Controller, Service, Repository를 만들었다.
public class Member {
@EmbeddedId
private MemberId id;
@Column(nullable=false)
private String name;
@Column(nullable=false)
private Integer age;
}
public class MemberController {
private final MemberService memberService;
@PostMapping
public ResponseEntity<Void> join(@RequestBody JoinRequest request) {
log.info("*** controller start ***");
memberService.join(request);
log.info("*** controller end ***");
return ResponseEntity.created(URI.create("/")).build();
}
}
public class MemberService {
public class MemberRepository memberRepository;
public void join(JoinRequest request) {
log.info("*** service start ***");
MemberId newId = new MemberId("M".concat(UUID.randomUUID().toString()));
Member newMember = Member.build()
.id(newId)
.name(request.getName())
.age(request.getAge())
.build();
log.info("registering new member..");
memberRepository.save(newMember);
log.info("*** service end ***");
}
}
@Column을 사용한 null check 구현 예제이다.
이 상태에서 request를 보낼 때, age항목을 제외하고 요청을 날려보았다.

로그를 확인해봤을때, controller에서 요청을 받고, service 메소드에서 엔티티를 생성한 후, repository를 통해 생성된 엔티티를 등록하는 과정에서 예외가 발생한다.
public class Member {
@EmbeddedId
private MemberId id;
@NonNull
private String name;
@NonNull
private Integer age;
}
이번에는 Member 엔티티에서 @NonNull을 사용해서 제약조건을 걸었다.

똑같은 요청을 전송했을때 발생한 로그이다.
여기서 봤을 때, service 내부에서 엔티티를 생성하는 과정에서 예외가 발생함을 확인할 수 있었다.
그래서 결론은,
Service 레이어에서 널체크가 가능한 @NonNull을 사용하는 것이 더 낫다!
위의 예시에서는 service 내부에서의 로직이 짧기때문에 크게 와닿지않았다.
하지만, 엔티티 생성이후 등록까지의 과정에서 로직이 많으면 많을수록 비효율적일것이라 생각했다.
무엇보다도 서비스 레이어 내에서 예외를 잡을 수 있는 것과 레포리토리 레이어까지 진행된 후에 예외를 잡는 것은 큰 차이라고 생각되었다. 가능하다면 controller단에서, 또는 Argument Resolver에서 널체킹이 이루어지는것이 베스트이지않을까 생각했다.
'Dev > 스프링' 카테고리의 다른 글
[스프링] 컴포논트 스캔 @ComponentScan (0) | 2022.04.25 |
---|---|
[스프링] 의존 자동 주입 & @Autowired 애노테이션 (0) | 2022.04.20 |
스프링에서 의존과 주입은 무엇이며 왜 써야할까? (0) | 2022.04.15 |
[스프링] 스프링의 빈, 컨테이너, 메이븐&그래들 (0) | 2022.04.11 |