새로운 객체를 저장할 때 @ColumnDefault를 사용하면 필드값을 초기화하지 않을 경우 null 값이 필드에 들어가 설정한 기본값으로 DB에 저장될 거라고 생각했는데 설정한 기본값으로 저장되지 않고, null으로 저장되는 문제가 발생하였다.
문제를 해결하기 위해 @ColumDefault에 대해 조금 더 찾아보았다.
@ColumnDefault
@ColumDefault는 ddl-auto 옵션으로 DDL을 생성할 때 자동으로 default 제약사항을 넣어주는 어노테이션이다.
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
@ColumnDefault("'L1'")
private String level;
}
실행 시 다음과 같은 DDL이 생성된다.
create table member (
id bigint generated by default as identity,
level varchar(255) default 'L1',
primary key (id)
)
그렇기 때문에 초기값을 넣지 않으면 설정한 값으로 초기화될 것이라고 예상했으나 다음과 같은 테스트 코드를 돌려보면, 테스트가 실패하고
@Test
public void test() throws Exception {
Member member = new Member();
Member findMember = memberRepository.save(member);
assertThat(findMember.getLevel()).isEqualTo("L1");
}
실제로는 다음과 같은 쿼리가 나가며 level이 null으로 초기화되어 저장되는 것을 확인할 수 있다.
[Hibernate]
insert
into
member
(level, id)
values
(?, default)
Expected :"L1"
Actual :null
결론적인 이유는 DB에서 null도 값으로 받아들이기 때문이다.
default 값은 아무런 값으로도 초기화되지 않은 경우에만 적용된다. 초기화를 하지 않으면 java에서는 기본적으로 null으로 초기화하기 때문에, DB에 저장 시 default 값이 아닌 null이 저장되는 것이다.
따라서 발생한 문제를 해결하는 방법으로는 두가지가 있는데
[1] @DynamicInsert를 사용하거나, [2] 필드값을 초기화 하는 것이다.
[1] @DynamicInsert
@DynamicInsert는 insert 쿼리를 날릴 때 null인 값은 제외하고 쿼리문을 생성하는 어노테이션이다.
해당 어노테이션을 Member entity의 클래스 레벨에 붙이고 member를 저장하면 null인 level 필드를 제외하고 쿼리문이 날라가는 것을 확인할 수 있다.
[Hibernate]
insert
into
member
(id)
values
(default)
[2] 필드값 초기화하기
@Column
@ColumnDefault("'L1'")
private String level = "L1";
이렇게 필드값을 먼저 초기화해주는 방법으로도 해결할 수 있다.
하지만 이 방법을 사용할 경우 @Builder를 이용하여 객체를 생성하는 경우에는 값이 초기화되지 않는다. 따라서 만약 @Builder를 이용하는 경우 @Builder.Default 어노테이션을 사용해서 필드를 초기화하여야 한다.
@Column
@ColumnDefault("'L1'")
@Builder.Default
private String level = "L1";
'Spring boot' 카테고리의 다른 글
| Spring boot에서 enum의 유연한 직렬화 및 역직렬화 (0) | 2025.11.14 |
|---|