Spring Boot와 JPA에서 발생한 'Field 'id' doesn't have a default value' 오류 해결 방법

신수정·2024년 5월 7일
0

서론

Spring Boot와 JPA를 사용하여 애플리케이션을 개발하는 과정에서 Field 'id' doesn't have a default value 오류를 만나는 경우가 종종 있습니다. 이 오류는 자동 증가 키가 제대로 설정되지 않은 경우 발생합니다. 이번 블로그에서는 이 오류의 원인과 해결 방법을 함께 살펴보겠습니다.

문제 상황

회원가입 기능을 구현하는 과정에서, 다음과 같은 User 엔티티를 작성했습니다.

package com.nado.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.util.HashSet;
import java.util.Set;

@Entity
@Getter
@Setter
public class User {

    @Id
    private Long id;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false, unique = true)
    private String nickname;

    @Enumerated(EnumType.STRING)
    private Status status;

    @Enumerated(EnumType.STRING)
    private Role role;

    @Column(nullable = false)
    private Boolean emailVerified;

    public enum Status {
        ACTIVE, INACTIVE, BANNED
    }

    public enum Role {
        USER, ADMIN
    }

    @OneToMany(mappedBy = "user")
    private Set<Post> posts = new HashSet<>();

    @ManyToMany
    @JoinTable(
            name = "user_followers",
            joinColumns = {@JoinColumn(name = "user_id")},
            inverseJoinColumns = {@JoinColumn(name = "follower_id")}
    )
    private Set<User> followers = new HashSet<>();

    @ManyToMany(mappedBy = "followers")
    private Set<User> following = new HashSet<>();
}

application.properties 설정

spring.jpa.hibernate.ddl-auto=update

이 상태에서 회원가입을 테스트하기 위해 데이터를 제출했을 때 다음과 같은 오류 메시지가 나타났습니다.

2024-05-07T20:28:09.046+09:00 ERROR 496 --- [nado] [nio-8090-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.orm.jpa.JpaSystemException: could not execute statement [Field 'id' doesn't have a default value] [insert into user (email,email_verified,nickname,password,role,status) values (?,?,?,?,?,?)]] with root cause

오류 원인

  1. 오류 메시지: Field 'id' doesn't have a default value

    • org.springframework.orm.jpa.JpaSystemException: could not execute statement [Field 'id' doesn't have a default value] [insert into user (email,email_verified,nickname,password,role,status) values (?,?,?,?,?,?)]]
    • 이 오류는 id 필드에 기본값이 없다는 것을 나타냅니다.
  2. 원인 분석

    • 엔티티의 id 필드에 @GeneratedValue 어노테이션이 없거나, 자동 증가 전략이 올바르게 설정되어 있지 않아 데이터베이스에 기본 키 값이 없는 상태로 삽입하려 할 때 발생하는 문제입니다.

해결 방법

  1. @GeneratedValue 어노테이션 추가
    • 자동 증가 키를 설정하기 위해 @GeneratedValue(strategy = GenerationType.IDENTITY) 어노테이션을 추가했습니다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
  1. 문제 여전히 발생

    • 하지만 @GeneratedValue(strategy = GenerationType.IDENTITY)을 추가한 후에도 같은 오류가 발생했습니다.
    • 이 문제는 application.properties에서 spring.jpa.hibernate.ddl-auto=update 설정이 되어 있기 때문에 발생했습니다.
    • 이 설정은 기존 데이터베이스 스키마를 수정하는 방식으로 동작하지만, 기본 키 생성 전략을 업데이트하지 않습니다.
  2. 해결 절차

    • 먼저 application.properties에서 spring.jpa.hibernate.ddl-autocreate-drop으로 변경하여 테이블 구조를 재생성했습니다.
spring.jpa.hibernate.ddl-auto=create-drop
  • 변경된 User 엔티티는 다음과 같습니다.
package com.nado.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.util.HashSet;
import java.util.Set;

@Entity
@Getter
@Setter
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false, unique = true)
    private String nickname;

    @Enumerated(EnumType.STRING)
    private Status status;

    @Enumerated(EnumType.STRING)
    private Role role;

    @Column(nullable = false)
    private Boolean emailVerified;

    public enum Status {
        ACTIVE, INACTIVE, BANNED
    }

    public enum Role {
        USER, ADMIN
    }

    @OneToMany(mappedBy = "user")
    private Set<Post> posts = new HashSet<>();

    @ManyToMany
    @JoinTable(
            name = "user_followers",
            joinColumns = {@JoinColumn(name = "user_id")},
            inverseJoinColumns = {@JoinColumn(name = "follower_id")}
    )
    private Set<User> followers = new HashSet<>();

    @ManyToMany(mappedBy = "followers")
    private Set<User> following = new HashSet<>();
}
  • 이 상태에서 서버를 실행하면 테이블이 새로 생성됩니다.
  • 이후 다시 application.properties에서 spring.jpa.hibernate.ddl-auto 설정을 update로 변경했습니다.
spring.jpa.hibernate.ddl-auto=update

최종 결과

이제 회원가입 테스트를 했을 때 오류 없이 실행되었습니다.

정리

Field 'id' doesn't have a default value 오류를 해결하기 위해서는 다음 사항을 확인해야 합니다.
1. @GeneratedValue(strategy = GenerationType.IDENTITY) 어노테이션을 추가하여 자동 증가 키를 올바르게 설정합니다.
2. application.properties에서 spring.jpa.hibernate.ddl-auto=create-drop 또는 create 설정을 사용하여 테이블을 처음부터 생성하거나 업데이트합니다.

  • create-drop: 애플리케이션이 시작할 때 테이블을 생성하고, 종료 시 테이블을 삭제합니다.
  • create: 애플리케이션이 시작할 때 테이블을 생성합니다.
  • update: 기존 테이블을 수정하지만, 기본 키 생성 전략을 변경하지는 않습니다.

이 포스트에서는 Spring Boot와 JPA를 사용해 엔티티의 기본 키를 자동 증가 키로 설정하고, 이와 관련된 오류를 해결하는 방법을 알아보았습니다. 앞으로 데이터베이스 설계 시 자동 증가 키를 활용해야 하는 경우, 반드시 @GeneratedValue 어노테이션을 함께 사용하세요.

profile
안녕하세요:)

0개의 댓글