JPA 의 구현체인 Hibernate 에서 제공하는 @ColumnDefault 어노테이션은 스키마를 생성할 때 default 값을 설정해주는 역할을 한다. 사용방법은 매우 간단한데 default 값을 지정해주고 싶은 컬럼에 Literal 값을 적어주면 된다.
이제 애플리케이션을 실행해주면 JPA 에서 생성해주는 DDL 쿼리에 default 'GENERAL' 이라는 값이 잘 들어가는것을 확인할 수 있다.
@DynamicInsert
@ColumnDefault 를 사용할 때, 해당 컬럼에 @Column(nullable = false)과 같이 null 을 허용하지 않는 제약조건을 걸어주었을때 조심해야 한다. 아래와 같이 Member 엔티티를 만들때 UserType 정보를 주지 않고 영속화하면 DataIntegrityViolationException 가 터지게 된다.
JPA 에서 insert 쿼리를 통해 값을 영속화시킬 때, 기본적으로 insert 쿼리에 기본적으로 모든 column 을 명시하게 된다. 만약 영속성 객체에 모든 Column 값이 제대로 채워지지않으면 아래와 같이 insert 쿼리에서 해당 column 에 null 값이 들어가게 된다. 하지만 이것은 nullable = false 에 위배되기 때문에 오류가 터지게 되는 것이다.
@ColumnDefault 는 다이렉트로 들어온 null 값을 디폴트 값으로 바꾸어주지 않는다.
@ColumnDefault 를 통해 DDL 에서 default 제약조건을 걸어주어도, insert 쿼리를 통해 null 이 직접적으로 들어오면 default 값으로 바꿔지지 않는다.
영속성 객체의 클래스단에 @DynamicInsert 를 명시해주면, 영속성객체를 영속화할 때 채워지지않은 column 들은 무시하게 되고, 아래와 같은 쿼리가 나가게 된다. 해당 쿼리가 나가게 되면 @ColumnDefault 에서 걸어준 default 제약조건으로 해당 쿼리의 userType 은 GENERAL 이 된다.
테스트 코드는 아래와 같이 짜볼 수 있다. 코드 Hightlight 된 부분을 보면, EntityManger 로 영속성 컨텍스트를 한번 비워주고 있다. 잘 생각해보면 객체에서는 UserType 을 비웠기 때문에 Null 인 상태이다. 하지만 DB 에서는 default 제약조건으로 인해 GENERAL 인 상태이다. 결과적으로 객체와 DB 와 Sync 가 맞지 않는 문제가 발생한다. 이를 해결하기 위해 ID 로 멤버를 찾아오는 쿼리가 한번 더 나가게 된다. (불필요한 쿼리)
이 Sync 가 맞지않는 해결방법으로는 @ColumnDafault 를 통해 default 값을 설정하되, 객체에도 default 값이 셋팅될 수 있도록 코드를 만들어주면 된다. 이렇게 만들어주면, 영속성컨텍트스틀 비우고 추가적인 불필요한 쿼리 필요없이 DB 와 객체의 Sync 를 맞출 수 있다.