• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

@NotBlank 와 @Id 의 불편한 동거?

22.08.23 22:13 작성 조회수 773

2

오늘도 호돌님의 강의를 베이스로 이것저것 만들던중

아래와 같은 에러를 발생시킵니다. 

 

--------------------------------------------------------------------------------

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction

 

at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:571)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743)

at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711)

at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654)

------------------------------------------------------------------------------------------------------------

 

결국 초기화 시키고 다시 조합해 나가던중 

NotBlank 때문임을 발견합니다. (주석처리해둠)

 

  @Id
@Column(name = "member_id")
// @NotBlank
private Long member_id;

 

저는 선의의 마음으로 Id도 꼭 필요한 값이야!

를 선언하고 NotBlank를 썼는데, 

그 마음을 부정당한 느낌이라 스프링에 매우 섭섭합니다. 

 

이유를 알면 좀만 덜 섭섭할거 같은데 어떻게 공부해야 사연을 알수 있을까요??

 

암튼 불철주야 감사합니다 ㅇㅇd

답변 1

답변을 작성해보세요.

5

안녕하세요. 호돌맨입니다.
질문을 남겨주셔서 감사합니다.

1. 재현과정

  1. 아래와 같은 소스일때 발생하는 오류

        @Id
        @Column(name = "id")
        @NotBlank
        private Long id;
    ids for this class must be manually assigned before calling save(): com.hodolog.api.domain.Post; nested exception is org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.hodolog.api.domain.Post
    org.springframework.orm.jpa.JpaSystemException: ids for this class must be manually assigned before calling save(): com.hodolog.api.domain.Post; nested exception is org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.hodolog.api.domain.Post
  2. @GeneratedValue를 넣은경우 발생하는 오류

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @NotBlank
    private Long id;
    HV000030: No validator could be found for constraint 'javax.validation.constraints.NotBlank' validating type 'java.lang.Long'. Check configuration for 'id'
    javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint 'javax.validation.constraints.NotBlank' validating type 'java.lang.Long'. Check configuration for 'id'
  3. 왜 오류가 다를까 생각해보니.. 수강민수께서는 id를 직접 set 해줬을거라 생각했습니다. 저도 Post.id를 직접 지정해봤습니다.
    역시! 수강민수님과 같은 오류가 발생했네요!

        @Id
        @Column(name = "id")
        @NotBlank
        private Long id;
    public void write(PostCreate postCreate) {
            Post post = Post.builder()
                    .title(postCreate.getTitle())
                    .content(postCreate.getContent())
                    .build();
    
            post.setId(100L); // id를 100으로 설정함
    
            postRepository.save(post);
        }
    Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
    org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction

2. 생각해보기

그렇다면 왜 오류가 발생했을까요?
힌트는 1-2에 있습니다.

그 이유는 바로... 두구두구두구...!!

그렇습니다! Long을 갖고 @NotBlank 검증을 할 수 없다는거죠!
그렇다면 @NotBlank가 어디에 쓰이는지 생각해볼 필요가 있습니다. (참고링크: https://sanghye.tistory.com/36)

그렇죠! @NotBlank는 null, "", " "와 같이 주로 String 타입을 검증하는데 쓰입니다.
문자열 검증 방식을 숫자타입에 적용하려고 하니 JPA가 개빢칠만합니다.

그렇다면 Long타입에 맞는 Validator를 넣으면 해결 될까요? 숫자에 맞는 검증 언노테이션은 뭔가 있을까요?!
'최소! 최대!' 바로 @Min, @Max등이 있겠죠?

저는 @Min을 아래와같이 사용해봤습니다.

@Id
@Column(name = "id")
@Min(1) // id가 1보다 큰지확인함 (테스트 케이스에서는 100으로 설정했습니다.)
private Long id;

야호! 정상적으로 통과!
수강민수님의 의도라면 @NotNull을 써보는 게 어떨까요?

3. 어떻게 알아냄?

아무튼 그건 그렇고!! 그렇다면 이런 오류는 과연 어떻게 알아내야할까?
사실 Intellij에 올라온 Exception 콘솔에 스크롤을 쭉 내려보면 Exception stack trace로 가 잡혀있습니다.

Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
... 생략
... 생략
UnexpectedTypeException: HV000030: No validator could be found for constraint 'javax.validation.constraints.NotBlank' validating type 'java.lang.Long'. Check configuration for 'id'

image
현재 발생한 예외(TransactionException)이 어떤 예외를 쳐 맞고 쭉~ 쌓이게 되었는지! 보이는거죠!
그렇기 때문에 콘솔을 확인하실때는 현재 예외뿐만 아니라
스크롤을 쭉~~ 내리셔서 어떤 오류로 부터 예외가 전파되었는지 확인하면! 내일은 나도 개발 짱!

감사합니다.

jcknow님의 프로필

jcknow

질문자

2022.08.27

아니, 그냥 힌트만 달라고 했는데 아얘 1강을 만드시면 이거 어쩝니까.........

이런다고 감사할줄 아신다면 그건 크나큰 오예입니다.

그랜절 올립니다 감사합니다

근데 그거 아십니까? 저도 제가 Id를 set하는 천인공로할 짓을 했다는걸 이걸 보고 알았습니다. ㄷㄷ

(정확히는 testcase만지작 거리다 set질을 하려 했군요...)

무의식에서나마 이런짓을 하는걸 보니 전 아직 멀었나봅니다.

다시한번 ㅅ 잡고 반성하며 강의한번 더 듣겠습니다.