JPA 기본전략을 이해하고 데이터베이스 Default 값 설정 및 데이터 저장 시 설정한 기본값으로 저장하는 방법에 대해 정리하고자 합니다.!!
문제 상황
Spring Data JPA 라이브러리 ORM을 통해 데이터베이스 기본값을 설정하는데 올바르게 설정되지 않는 문제가 있었습니다.
기존 코드
@Entity
@Getter
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "application_tb")
public class Application extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "application_id", nullable = false)
private Long id;
@Column(nullable = false)
private Integer workYears = 0;
@Column(nullable = false, length = 1)
private Character isSingleParent = '0';
@Column(nullable = false)
private Integer childrenCnt = '0';
@Column(nullable = false, length = 1)
private Character isDisability = '0';
@Column(nullable = false, length = 1)
private Character isDualIncome = '0';
}
문제점
- @Builder를 통한 객체 생성
- 빌더 패턴은 명시적으로 값을 설정하지 않은 필드는 기본값으로 설정하지 않습니다. @Builder.Default로 값을
명시해주어야 함
- 빌더 패턴은 명시적으로 값을 설정하지 않은 필드는 기본값으로 설정하지 않습니다. @Builder.Default로 값을
- 기본값 설정 오류
- 자바 코드에서는 기본값이 설정되었지만, 데이터베이스에는 기본 값이 설정되지 않았기에 @ColumnDefault로
데이터베이스 기본값을 설정해 주어야 함
- 자바 코드에서는 기본값이 설정되었지만, 데이터베이스에는 기본 값이 설정되지 않았기에 @ColumnDefault로
문제 해결
방법 1 - @DynamicInsert, @ColumnDefault 사용하기
@Entity
@Getter
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@DynamicInsert
@Table(name = "application_tb")
public class Application extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "application_id", nullable = false)
private Long id;
@Column(nullable = false)
@ColumnDefault("'0'")
private Integer workYears;
@Column(nullable = false, length = 1)
@ColumnDefault("'0'")
private Character isSingleParent;
@Column(nullable = false)
@ColumnDefault("'0'")
private Integer childrenCnt;
@Column(nullable = false, length = 1)
@ColumnDefault("'0'")
private Character isDisability;
@Column(nullable = false, length = 1)
@ColumnDefault("'0'")
private Character isDualIncome;
}
JPA 업데이트 기본 전략 이해하기
JPA는 특정 부분을 업데이트해도 기본적으로 모든 필드를 업데이트합니다.
=> 모든 필드를 업데이트하면 데이터베이스에 보내지는 데이터 전송량이 많아져 단점이 있지만, 몇몇 장점이 있어 JPA에서는
기본적으로 모든 필드를 업데이트 하고 있습니다.
- 모든 필드를 업데이트하면 바인딩 되는 데이터만 다를 뿐 등록/수정 쿼리가 항상 같아집니다. 따라서 애플리케이션 로딩
시점에 쿼리를 미리 생성해두고 재사용할 수 있습니다. - 데이터베이스에 동일한 쿼리를 보내면 데이터베이스는 이전에 한 번 파싱 된 쿼리를 재사용할 수 있습니다.
모든 필드를 업데이트하는 것이 아닌 특정 필드만 업데이트하고 싶은 경우
@DynamicInsert, @DynamicUpdate 사용하기
@ColumnDefault 이해하기
@ColumnDefault는 해당 필드 값에 대한 default 값을 설정할 수 있는 어노테이션입니다.
즉, 선언되어 있는 칼럼의 값을 채우지 않으면, 미리 default로 지정해 놓은 값으로 값을 설정합니다.
하지만, 별도의 설정 없이 @ColumnDefault를 사용하면 의도했던 결과가 나오지 않는다!
그 이유는 해당 어노테이션은 필드 값이 아무 값도 저장되지 않을 때 적용할 수 있는데, JPA 기본 전략 사용 시 모든 필드에 대한 쿼리가 적용되어 빈 값인 경우 null 값이 채워져 원하는 값으로 설정이 되지 않습니다.
그래서 @DynamicInsert를 사용하여 설정한 @ColumnDefault 값으로 데이터베이스에 기본값을 설정합니다.
@DynamicInsert
Hibernate의 어노테이션으로, INSERT 쿼리를 동적으로 생성할 때 사용됩니다.
이 어노테이션을 클래스에 적용하면, Hibernate는 INSERT 쿼리에서 null이 아닌 필드만 포함하여 쿼리를 생성합니다.
이로 인해, null인 필드에는 데이터베이스에서 정의된 기본값이 자동으로 적용됩니다.
방법 2 - @Builder.Default, @ColumnDefault 사용하기
@Entity
@Getter
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "application_tb")
public class Application extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "application_id", nullable = false)
private Long id;
@Builder.Default
@Column(nullable = false)
@ColumnDefault("'0'")
private Integer workYears;
@Builder.Default
@Column(nullable = false, length = 1)
@ColumnDefault("'0'")
private Character isSingleParent;
@Builder.Default
@Column(nullable = false)
@ColumnDefault("'0'")
private Integer childrenCnt;
@Builder.Default
@Column(nullable = false, length = 1)
@ColumnDefault("'0'")
private Character isDisability;
@Builder.Default
@Column(nullable = false, length = 1)
@ColumnDefault("'0'")
private Character isDualIncome;
}
@Builder.Default는 빌더 패턴을 사용할 때 기본값을 설정해 줍니다.
해당 어노테이션을 통해 객체를 생성하고 데이터베이스에 값을 저장할 때 기본값을 설정해 데이터를 저장할 수 있습니다.
'Spring Framework > JPA' 카테고리의 다른 글
[JPA] JPA 영속성 전이란, CASCADE.ALL 사용법, 연관관계 편의 메소드란 (0) | 2023.12.08 |
---|---|
[JPA] JPA 상속 관계 매핑과 @MappedSuperClass 사용하기 - 조인전략, 싱글 테이블, @CreatedDate, @LastModifiedDate (1) | 2023.11.28 |
[JPA] JPA 페치조인과 DISTINCT - 컬렉션 페치 조인 데이터 중복 문제 해결 (0) | 2023.11.17 |
[JPA] 연관관계 매핑, 양방향, 연관관계 주인, mappedBy (0) | 2023.11.11 |
[JPA] Spring JPA 프록시 객체와 지연로딩이란 무엇인가, 사용하는 이유 (1) | 2023.10.09 |