리뷰 엔티티에서 ColumnDefault를 사용해 리뷰를 만들 때 rating을 0으로 초기화 하고자 했는데 아래와 같은 에러를 마주하였다.
java.sql.SQLException: Column 'rating' cannot be null
자바의 rating 값이 null 로 전달된 것이다. 왜 이렇게 되었을까?
@ColumnDefault()
필자가 사용한 코드는 아래와 같다. ColumnDefault에 값이 0으로 올바르게 설정되어 있다.
@Column(nullable = false)
@ColumnDefault("0")
private Integer rating;
하지만 hibernate에선 create-drop일 때만 default 쿼리를 날린다.
그렇기 때문에 컬럼에 default 설정이 되지 않았고, 기본값이 들어가지 않았던 것이다. 그렇다면 해결 방법은 무엇일까?
1. @PrePersist
JPA에는 엔티티 라이프 사이클의 콜백 컨트롤 어노테이션인 @PrePersist, @PostPersist, @PreRemove 등이 있다. 이름에 맞게 엔티티를 생성하면 @PrePersist 가 달린 메서드들이 호출되고, DB에 삽입된 후 @PostPersist가 달린 메서드들이 호출된다.
@Entity
@Getter
@RequiredArgsConstructor
public class Review {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
pritave String content;
@PrePersist
public void setting(){
this.content = "content";
System.out.println(id);
}
@PostPersist
public void printId(){
System.out.println(id);
}
위 예제를 실제로 실행하면 아래와 같이 rating이 정상적으로 0값이 되는 것을 볼 수 있다. 포스트 맨으로 요청을 보내보면 아래와 같이 잘 생성되는 것을 확인할 수 있다.
2. @DynamicInsert
DynamicInsert는 쿼리가 날아갈 때, null인 구문을 빼고 쿼리를 날려준다. 그렇기 때문에 null 값이 전달되지 않고 기본 값인 0이 등록된다. 실제로 값을 날려보면 아래와 같이 Response에 rating이 포함되지 않고 돌아오는 것을 볼 수 있습니다. 쿼리에 null이 포함되지 않기 때문입니다.
저는 @DynamicInsert를 사용하기로 했습니다. 이유는 다음과 같습니다.
- 실제 프로덕션 환경에선 hibernate로 테이블을 만들지 않고 SQL로 만들기 때문에 default값이 지정되어 있어서 쿼리에 null값만 보내지 않으면 정상적으로 처리됩니다.
- 보일러 플레이트 코드가 필요하지 않아 유지보수 측면에서 유리합니다.
둘 중 어떤 것을 사용하는가는 개발자의 자유이기 때문에 참고용으로만 생각해 주시길 바랍니다.