대용량 데이터 (csv파일) db에 넣기 with JdbcTemplate -2

2025. 12. 19. 14:34·프로젝트/끼니콩

2025.07.15 - [프로젝트/끼니콩] - [Spring] csv파일 db에 넣기 with JdbcTemplate

 

[Spring] csv파일 db에 넣기 with JdbcTemplate

들어가며아동급식카드가맹점 데이터를 db에 넣어야한다. 데이터는 지역 별로 나누어져 csv파일 형태로 제공되었고, 한 번만 넣는게 아니라 데이터가 변경되거나 지역이 확장이되면 계속적으로

erika0915.tistory.com

 

앞서 진행한 작업에 대한 설명이 적혀 있다. 


문제점

아동급식카드가맹점 공공데이터는 간헐적으로 업데이트된다. 가맹점의 정보가 수정되기도 하고, 없어지기도 하며, 새롭게 추가되기도 한다. 지금 운영하고 있는 '끼니콩' 서비스에서는 아래 사진과 같이 `업데이트 날짜`를 제공한다. 이는 해당 가맹점이 언제 마지막으로 업데이트가 되었는지를 나타낸다. 

 

공공데이터에 의존하고 있는 서비스기에, 해당 정보의 정확성을 보장하지 못한다. 그래서 업데이트 날짜를 제공함으로써 사용자들이 이 가맹점에 대한 정보가 언제 정보인지 파악하게끔 하는 역할인 것이다. 또한 옆에 `가게 수정 요청하기`를 통해서 그 가게에 대한 정보가 정확하지 않은 경우 데이터 업데이트를 요청할 수 있도록 제공하고 있다. 

kkinicong.co.kr

아무튼, 시간이 지남에 따라 공공데이터는 새롭게 업데이트가 되며 '끼니콩' 서비스 내에서도 이 업데이트를 지원해줘야 한다. 결국, csv 파일을 db에 넣는 작업이 단발성이 아닌, 같은 지역의 가맹점 정보도 지속적으로 업데이트해서 넣어주어야 한다는 것이다. 

 

 

 

그러나 나의 기존 코드는 업데이트와 관련된 구체적인 작업을 수행하지 못한다. '가맹점명'과 '주소'를 key로 설정해서 동일한 가맹점 정보가 또 다시 들어오면 db에 저장되지 않도록 설정은 해놓았지만, 가맹점의 정보가 변경되거나 가맹점이 없어졌을 경우에는 대응하지 못하는 문제점이 있다. 


요구사항 

다음과 같은 요구사항이 존재한다. 
- 기존에 새롭게 들어오는 가맹점들은 저장되어야 한다. 
- 기존에 존재하는 가맹점이지만, 새롭게 들어오는 csv 파일에는 해당 가맹점이 없다면 삭제되어야 한다. 
- 기존에 존재하는 가맹점 중, 새롭게 들어오는 csv 파일에 해당 가맹점에 대한 정보가 변경되었다면 변경된 값들만 변경한다. 

 

수정 방향 

1) 도메인 : Store 엔티티 

  • 플래그 필드인 `is_updated`를 추가하였다. 이는 동기화 과정에서 현재 파일에 포함된 데이터인지 아닌지를 구별하는 표식이다. 
  • 복합 유니크 인덱스인 `idx_name_address`를 설정하였다. `name`과 `address`를 묶어서 유니크 설정을 함으로써 db가 이름과 주소가 같으면 동일한 가게라고 인식하게 된다. 
  • 인덱스 `idx_region_is_updated`를 설정하였다. 이는 삭제할 때랑 리셋할 때의 쿼리를 보면 `region`과 `is_updated`를 조건으로 사용하는데, 이 인덱스가 없다면 db에서 삭제할 대상을 찾기 위해 테이블 전체를 full table scan하지만 인덱스를 사용해서 해당 지역의 `FALSE` 데이터만 집어서 빠르게 처리할 수 있다. 

여기서 주의해야할 점은 연관관계를 보존해야한다는 것이다. `review` 및 `storescrap` 등 연관관계가 존재하기 때문에 기존 가맹점의 `id`를 유지하며 업데이트해야한다. 

 

2) `StoreJdbcRepositoryImpl`

두 가지 메서드가 존재한다. 

1) `upsertStores` 

데이터를 삽입하고 갱신하는 역할을 한다. 여기서는 MySQL의 `ON DUPLICAATE KEY UDPATE` 구문을 활용한다. 

  • 신규 데이터는 유니크 키 (이름+주소)가 겹치지 않으면 `INSERT`가 수행된다. 이때, 앞서 도메인에서 설정한 `is_updated = TRUE`로 들어가게 된다. 
  • 기존 데이터는 유니크 키가 겹치면 에러를 내는 것이 아니라 `UPDATE`를 수행한다. 
    • `category` , `latitude`, `longitude`, `updated_date` 중 변동 가능한 정보만 갱신한다. 
    • 중요한 점은 `is_updated = TRUE`로 상태를 변경하여 이 데이터가 이번 파일에 존재했음을 표시한다.

2) `deleteMissingStores`

폐업되거나 더 이상 가맹점이 아닌 정보를 삭제하는 역할을 한다. 

  • 삭제 : `region = :region AND is_updated = FALSE` 조건을 통해, 방금 업로드한 지역 데이터 중 파일에 없어서 `TRUE`가 되지 못한 데이터만 골라 삭제한다. 
  • 리셋 : 삭제 후, 남은 데이터들의 `is_updated`를 다시 `FALSE`로 초기화한다. 그래야 다음 번 업로드 시 다시 비교를 시작할 수 있기 때문이다. 

3) 서비스 레이어 : `StoreUploadService` 

전체적인 비즈니스 흐름과 로그가 존재한다. 


https://github.com/Heroineeee/BE/pull/119

 

[FEAT] 가맹점 정보 업데이트 및 동기화 로직 구현 by erika0915 · Pull Request #119 · Heroineeee/BE

📝 개요 이미 db에 존재하는 지역에 대해 업데이트된 공공데이터의 csv 파일을 업로드 했을 때의 로직을 고려하여 csv 파일 업로드 로직을 구현했습니다. 🛠️ 작업 사항 가맹점 데이터 upsert 기

github.com

 

'프로젝트 > 끼니콩' 카테고리의 다른 글

[k6] 부하테스트  (0) 2025.11.04
[JVM] JVM GC 튜닝  (0) 2025.10.14
'프로젝트/끼니콩' 카테고리의 다른 글
  • [k6] 부하테스트
  • [JVM] JVM GC 튜닝
erika0915
erika0915
백엔드 개발자가 되고 싶어요 .
  • erika0915
    erikoding
    erika0915
  • 전체
    오늘
    어제
    • 분류 전체보기 (78)
      • 프로젝트 (13)
        • 끼니콩 (3)
        • 덕메랑 (3)
        • handDoc (7)
        • Haeil (0)
      • Java (9)
        • 클린코더스 (0)
      • Spring (30)
      • Redis (3)
      • CS (7)
        • 운영체제 (3)
        • 컴퓨터구조 (0)
        • 네트워크 (4)
      • DevOps (2)
      • 코딩테스트 (0)
      • Tech (14)
        • TDD (1)
        • 정리 (5)
        • 우테코 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    몽고디비
    springboot
    OS
    코드레빗
    지라
    promtail
    java
    도커
    운영체제
    coderabbit
    Spring
    자바
    깃
    TDD
    깃허브
    스프링부트
    docker
    CoolSMS
    네트워크
    MongoDB
    레디스
    파인튜닝
    github
    STT
    redis
    git
    AI
    스프링
    Network
    jira
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
erika0915
대용량 데이터 (csv파일) db에 넣기 with JdbcTemplate -2

티스토리툴바