JPA 더미데이터 생성 방법

JinYoung Choi·2023년 6월 5일
0
post-thumbnail

프로젝트를 진행하면서, 실제 서비스를 위한 데이터가 아직 준비되지 않았거나 테스트 목적으로 대량의 데이터가 필요한 경우가 종종 있다.

이럴 때 사용하는 것이 바로 더미 데이터이다.
더미 데이터는 실제 데이터와 비슷한 형태로 만들어진 가짜 데이터로, 개발을 진행하면서 다양한 시나리오를 시험하거나 성능을 체크하는데 사용된다.

이번 글에서는 이런 더미 데이터의 생성 방법에 대해 자세히 알아보도록 하겠다.

ddl-auto

먼저 ddl-auto에 대해 알아야 한다.

ddl-auto는 Spring Boot의 JPA 설정에서 사용되는 속성 중 하나이다.
이 속성은 데이터베이스 스키마 생성 전략을 설정하는 데 사용되며, 다음과 같은 옵션들을 제공한다.

none : 기본 설정값으로, Hibernate가 데이터베이스 스키마를 생성하지 않는다.
validate : Hibernate가 애플리케이션을 실행할 때 Entity와 데이터베이스 테이블이 일치하는지 확인한다.
update : 데이터베이스 스키마를 애플리케이션 실행 시 자동으로 수정하도록 한다. 만약 Entity에 새로운 필드가 추가되면, 이에 대한 새로운 컬럼이 데이터베이스 테이블에 추가된다.
create : 애플리케이션 실행 시마다 데이터베이스 스키마를 생성하고, 종료 시에는 스키마를 삭제한다.
create-drop : create 옵션과 비슷하지만, 애플리케이션 종료 시에 데이터베이스 스키마를 삭제한다.

주의 - 실제 운영 환경에서는 ddl-auto 설정을 none 또는 validate로 설정해야 한다

개발 도중에 더미데이터를 활용하기 위해선 schema.sql 파일과 data.sql 파일을 이용해 데이터베이스 스키마와 더미 데이터를 생성할 수 있는데 이때 Hibernate의 ddl-auto 속성이 none 또는 create로 설정되어 있어야 한다

application.yml 설정

  jpa:
    hibernate:
      ddl-auto: create-drop
    defer-datasource-initialization: true
  sql:
    init:
      data-locations: classpath*:db/data.sql
      mode: always
      platform: h2 
  • ddl-auto: create-drop: 이 옵션은 Hibernate가 자동으로 테이블을 생성하고, 애플리케이션 종료시 테이블을 삭제하게 한다.

  • defer-datasource-initialization: true: 이 설정은 Spring Boot가 데이터 소스 초기화를 지연시키도록 한다. 이는 JPA 엔티티를 데이터베이스 스키마에 매핑하기 전에 SQL 스크립트를 실행할 수 있게 한다.

  • sql.init.data-locations: classpath*:db/data.sql: 이 설정은 더미 데이터를 삽입하기 위한 SQL 스크립트의 위치를 지정한다. 이 파일은 애플리케이션 시작 시 자동으로 실행된다.
    위치를 지정해주지 않는다면 hibernate에서 resources 폴더에 import.sql을 알아서 찾아 실행시킨다.

  • sql.init.mode: always: 이 설정은 애플리케이션 재시작마다 SQL 스크립트를 실행하게 한다.

  • sql.init.platform: h2: 이 설정은 SQL 스크립트가 실행될 데이터베이스 플랫폼을 지정한다. 여기서는 H2 데이터베이스가 선택되었다.

이렇게 설정 해주면 더미데이터를 사용하기 위한 준비는 끝났다.

data.sql 파일 생성

resources/db 폴더에 data.sql을 생성한다.

다음과 같은 review 테이블이 있다면

@NoArgsConstructor
@Getter
@Setter
@Entity
public class Review extends Auditable {

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

    private String title;


    private String content;

    private double rating;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ITEM_ID")
    private Item item;

    @OneToMany(mappedBy = "review",cascade = CascadeType.ALL)
    private List<ReviewImage> reviewImages = new ArrayList<>();

    public void addImage(List<ReviewImage> images){
        for (ReviewImage image : images) {
            reviewImages.add(image);
            if(image.getReview() != this){
                image.setReview(this);
            }
        }
    }

    public void addMember(Member member){
        this.member = member;
        if(!member.getReviews().contains(this)){
            member.getReviews().add(this);
        }
    }

    public void addItem(Item item){
        this.item = item;
        if(!item.getReviews().contains(this)) {
            item.getReviews().add(this);
        }
    }

    // 기존에 연결된 이미지 모두 제거 하고 연결 정보 업데이트
    public void clearImages() {
        reviewImages.forEach(image -> image.setReview(null));
        reviewImages.clear();
    }
}

data.sql 에 INSERT 쿼리문을 작성하면 완성!

INSERT INTO review (CREATED_AT, LAST_MODIFIED_AT, CONTENT, RATING, TITLE, ITEM_ID, MEMBER_ID)
       ('2023-05-16 15:48:57.450179', '2023-05-16 15:48:57.450179', '꿀!', 5.0, '와 맛있당!', 2, 1),
       ('2023-05-16 15:49:30.000000', '2023-05-16 15:49:30.000000', '맛있어요!', 4.0, '맛있어요!', 1, 1),
       ('2023-05-16 15:50:00.000000', '2023-05-16 15:50:00.000000', '별로에요!', 2.5, '별로에요!', 1, 2),
       ('2023-05-16 15:50:30.000000', '2023-05-16 15:50:30.000000', '좋아요!', 4.5, '좋아요!', 1, 2),
       ('2023-05-16 15:51:00.000000', '2023-05-16 15:51:00.000000', '괜찮아요!', 3.0, '괜찮아요!', 1, 2);
profile
백엔드 취준생

0개의 댓글