@Notfound

Seunghyeon·2025년 4월 21일
0

Spring정리

목록 보기
1/2
post-thumbnail

문제 상황

개발을 하다가 엔티티 내부에 연관관계로 매핑된 다른 엔티티를 불러올 때 column 값은 있지만 해당 데이터가 DB에서 없는 데이터일 경우
쿼리 단에서 예외가 발생한다. 이를 어떻게 해결해야 할까?

1. Board 에서 User의 엔티티를 들고있을 때


//Board 엔티티 내부 필드
	@ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    private User user;

Board 라는 엔티티 내부의 user 필드이다.

만약 user_id 가 null 인 값이 들어오면 어떻게 되나?
(board 테이블에 한 튜플의 user_id 컬럼이 null 인 경우)

-> 이런 경우 FetchType.LAZY, EAGER에 관계없이 찾으려는 시도조차 안한다.

즉 user_id에 null 값이 들어있으면 그냥 Board만 딱 들고 온다는 것

그러면 user에는 null이 들어가있는다.

그리고 이는 optional 이라는 옵션이 true로 기본적으로 설정되어 있기 때문 (디폴트가 true라 안보임)

//Board 엔티티 내부 필드
	@ManyToOne(fetch = FetchType.EAGER, optional = true)
    @JoinColumn(name = "user_id")
    private User user;

핵심은 시도조차 안한다는 것 -> 쿼리가 안날아가니 문제될 게 없음.

위 경우에서 user에 접근하는 로직이 있다면?

당연히 NPE가 발생할 것이다.

그럼 필드를 Optional<User>로 만들어 주면 되겠네? -> X

Optional은 엔티티 필드에 쓰면 안된다고 한다. (JPA 스펙상 그렇다고 함, JPA에서 사용 금지함)

그럼 어떻게 하지...


서비스단에서 Optional로 가야 한다.

Optional<User> optionalUser = Optional.ofNullable(board.getUser());

이렇게 통하면 null-safe 하게 사용할 수 있다.

-> 하지만 나는 null 체크를 잘 해야한다는 설명을 하고있는게 아니다.


2. Board 내부 User id가 "존재할 때"


설명하고 싶은 상황은 이러한 상황이다.

  1. Board 내부에는 User가 매핑되어 있다.
  2. user_id pk 값으로 DB에서 찾게된다.
  3. Board 테이블 내에는 user_id로 '10' 이라는 값이 존재한다.
  4. User 테이블에서 pk 10을 가진 user는 없는 경우

일반적으로 구현할 때 유저가 회원 탈퇴를 하면 soft_delete를 한다.

"is_delete" 라는 컬럼을 User에 두고 삭제가 된다면 true 로 바꿔주는 그런식의 삭제 로직을 사용하는데

이러한 세부적인 정책은 결국 고객의 요구사항에 맞게 반영해야 하는 부분이기 때문에 달라질 수 있다.

그래서 해당 프로젝트에서는 회원 탈퇴 시 hard-delete 즉 데이터를 삭제하는 방향으로 구현하게 되었다.

Board 엔티티를 가져오면 fetchType에 따라 User를 바로 가져올 수도 있고, 아니면 필요할때 가져올 수 있다.

결국 User 엔티티를 조회하게 되는데 이 때 "user_id" 기반으로 찾을 수 없는 데이터라면???

-> SQL 에러가 발생한다.

이를 어떻게 해결했나?


@notfound(action = notfoundaction.ignore)


이는 JPA의 기능은 아니고 hibernate에서 지원하는 기능이다.

hibernate 공식문서 링크

//Board 엔티티 내부 필드
	@ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    @notfound(action = notfoundaction.ignore)
    private User user;

만약 user_id로 DB에서 검색을 했더니 데이터가 없는 데이터다? 그러면 예외를 발생시키지 말고 null을 넣어라

라는 어노테이션이다.

마치 Java Optional을 트랜잭션에 적용한 느낌이다.

나는 이런 어노테이션을 사용해서 예외 처리를 할 수 있었다.

profile
그냥 합니다.

0개의 댓글