일단 더미데이터란?
특정 데이터를 테스트나 데모용도로 사용하기 위해 임의로 만든 데이터입니다!
저희도 과제를 하고 API를 작성함에 있어서 더미데이터를 넣어주고 test하는것이 필요한 경우가 많죠!
하지만 저도 이런점들을 잘 몰랐을때 그냥 Main코드에 더미데이터를 추가하는 코드를 넣거나 그냥 test API마다 값을 달리해서 추가하는 경우가 종종 있었습니다!!
따라서 아래와 같은 방식을 사용해서 더미데이터를 집어넣는다면 코드를 좀더 간결하고 작업하기 쉽게 만들수 있겠죠??
1. data.sql
스프링 부트에서 (src/main/resource) 안에 만들어주시면 어플리케이션 "실행"시에 자동으로 실행됩니다!
다음과 같이 쿼리문을 만들어서 실행시켜주면 자동으로 더미데이터를 만들수가 있습니다!
어떻게 만들어야할지 모르겠다면 그냥 GPT한테 물어봅시다! 저희 !
DROP TABLE IF EXISTS product;
CREATE TABLE PRODUCT
(
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(20) NOT NULL,
img_url VARCHAR(255),
price INT NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO PRODUCT (name, img_url, price)
values ('피자',
'https://cdn.dominos.co.kr/admin/upload/goods/20200311_x8StB1t3.jpg',
13000);
INSERT INTO PRODUCT (name, img_url, price)
values ('샐러드',
'https://m.subway.co.kr/upload/menu/K-%EB%B0%94%EB%B9%84%ED%81%90-%EC%83%90%EB%9F%AC%EB%93%9C-%EB%8B%A8%ED%92%88_20220413025007802.png',
20000);
INSERT INTO PRODUCT (name, img_url, price)
values ('치킨',
'https://cdn.thescoop.co.kr/news/photo/202010/41306_58347_1055.jpg',
10000);
2. @PostCounstruct
PostConstruct? 말 그대로 의존성 주입이 "이루어진 후" 초기화를 수행하는 어노테이션입니다!
이러한 @PostConstruct는 bean의 lifecycle에서 오직 한번만 수행된다는것을 보장하기 때문에 Bean이 여러번 초기화되는것을 방지할수 있고 이러한 점이 더미 데이터를 만드는 데에도 유용하게 사용할수 있겠죠??
@Component
public class ProductInitializer {
private final ProductDao productDao;
public ProductInitializer(ProductDao productDao) {
this.productDao = productDao;
}
@PostConstruct
public void init() {
// 더미 데이터 작성
Product pizza = new Product(
"피자",
"https://cdn.dominos.co.kr/admin/upload/goods/20200311_x8StB1t3.jpg",
13000);
Product salad = new Product(
"샐러드",
"https://m.subway.co.kr/upload/menu/K-%EB%B0%94%EB%B9%84%ED%81%90-%EC%83%90%EB%9F%AC%EB%93%9C-%EB%8B%A8%ED%92%88_20220413025007802.png",
20000);
Product chicken = new Product(
"치킨",
"https://cdn.thescoop.co.kr/news/photo/202010/41306_58347_1055.jpg",
10000);
// 더미 데이터 저장
productDao.save(pizza);
productDao.save(salad);
productDao.save(chicken);
}
}
여기서는 Dao에 넣어주었지만 우린아직 repo를 사용하니 repo로 사용하셔도 무방합니다!
즉 어플리케이션 실행시에 빈의 의존성주입 끝난 후! @PostContruct 메소드들이 실행되면서 더미데이터가 추가될수 있겠죠!
BUT, 큰 단점이 존재하는데요
위와 같은 방식은 @Transactional 어노테이션 적용이 불가능합니다. ㅠㅠㅠㄲ끼잉
스프링부트의 작동방식을 생각하면 아래와 같은 방식으로 진행되기 때문이죠ㅠㅠ
- 초기화 코드 실행
- 트랜잭션 AOP 적용
하지만 빠르고 간단하게 transactional이 딱히 없어도 되겠는데 ? 하는 경우에는 사용할수 있겠죠? 아직 엔터프라이즈급 코드를 통해서 엄청난 양의 데이터가 들어가 데이터 로직을 알수없는 경우가 아니라면 사용해도 무방은 할것 같습니다..
3.@EventListner(ApplicationReadyEvent.class)
@Transcationl이 적용 가능한 방법!
@EventListener(ApplicationReadyEvent.class)
@Transactional
public void init() {
// 더미 데이터 저장 로직
}
위와 같은 방법은 언제 작동할까요?
@EventListener ?? ->이게 좀 중요해 보입니다!!
ApplicationReadyEvent는 바로바로 스프링 컨테이너가 모두 띄워졌을때 발생하는 이벤트입니다!
스프링 컨테이너가 모두 완성되고 Bean, AOP 등을 모두 완성한 Application Context가 완성된 후 , EventLister를 통해서 ApplicationReadyEvent 클래스를 받게 되면서 다음 메소드를 수행하게 되는 것이죠!
따라서 이러한 방식덕분에 @Transactional 어노테이션을 사용할수 있습니다!
저희는 과제할때 그러면 이러한 부분을 따로 빼내고 Config나 다른 클래스로 빼서 Init 방식으로 사용할수 있습니다!!
4. ApplicationRunner
스프링부트의 내장형 톰캣, 웹컨테이너가 존재하기 때문에 내장형 톰캣이 시작될때 @ApplicationRunner 어노테이션을 붙인 메소드를 사용할수도 있습니다!
Application Runner는 어플리케이션 시작 시점에 실행이 되는데요, 이때문에 더미 데이터 추가 , 혹은 초기화 작업을 수행하는 작업을 수행하기 좋은 어노테이션입니다!
@Component
public class ProductInitializer implements ApplicationRunner {
private final ProductDao productDao;
@Autowired
public ProductInitializer(ProductDao productDao) {
this.productDao = productDao;
}
@Override
public void run(ApplicationArguments args) {
// 더미 데이터 작성
Product pizza = new Product("피자", "https://cdn.dominos.co.kr/admin/upload/goods/20200311_x8StB1t3.jpg", 13000);
Product salad = new Product("샐러드", "https://m.subway.co.kr/upload/menu/K-%EB%B0%94%EB%B9%84%ED%81%90-%EC%83%90%EB%9F%AC%EB%93%9C-%EB%8B%A8%ED%92%88_20220413025007802.png", 20000);
Product chicken = new Product("치킨", "https://cdn.thescoop.co.kr/news/photo/202010/41306_58347_1055.jpg", 10000);
// 더미 데이터 저장
productDao.saveProduct(pizza);
productDao.saveProduct(salad);
productDao.saveProduct(chicken);
}
}
이것처럼 ApplicationRunner를 구현한 클래스를 생성하고 초기화 class로 사용하면 되는 방식입니다!
그럼 이거 아무데나 작성하면 되는건가용?
음 그래도 될거 같은데요
스프링 부트의 프로젝트 구조상 패키지를 구조화해 관리하기 때문에 더미데이터를 추가해야 한다면 다음 해당하는 레이어 패키지에 위치시켜야 한다고 하네요 ?
예를 들어서 우리가 과제로 제출한 MemberRepository에 더미데이터를 추가해야 하죠?
따라서 MemberRepository 가 있는 패키지 내부에 작성하는 것이 좋다고 하네요
또한 더미데이터 추가가 여러 레이어에서 이루어진다면 보통 config.dataLoader 같은 이름의 클래스를 생성하여 각 레이어 별로 필요한 데이터를 추가한다고 합니다.!!
그럼 다들 더미데이터를 추가해 넘겨줄때 API 예시로 편하게 보여줄수 있도록 해봅시다!!!
! 굿!
'Spring' 카테고리의 다른 글
Spring 검색조회 필터링 구현 방법 [JPA Specification] (0) | 2024.07.31 |
---|---|
편리한 객체간 매핑을 위한 MapStruct 적용기 .feat 당근클론코딩 (1) | 2024.05.08 |
JPA - 단방향? 양방향? OneToMany? ManyToOne? (3) | 2024.04.29 |
@ManytoOne, @ManytoMany, @OnetoOne, @OnetoMany? (2) | 2024.04.28 |
SpringBoot와 Docker Container :Postgresql 연결하기! (2) | 2024.04.22 |