๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

ํ”„๋กœ์ ํŠธ/Airbnb Clone

[ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…] 20๋งŒ ๋”๋ฏธ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…์„ csvํŒŒ์ผ์„ ์ด์šฉํ•ด์„œ DB connection timeout → 7์ดˆ๋กœ ์ค„์ด๊ธฐ

โญ์„œ๋ก 

์ฝ”๋“œ์Šค์ฟผ๋“œ ์—์–ด๋น„์•ค๋น„ ํด๋ก  ์ฝ”๋”ฉ ํ”„๋กœ์ ํŠธ ์ค‘ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๊ณ  ์‹ถ์—ˆ๊ณ ,

์ด๋ฅผ ์œ„ํ•ด ๋‹ค๋Ÿ‰์˜ ์ˆ™์†Œ, ์˜ˆ์•ฝ, ํšŒ์›์˜ ๋”๋ฏธ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค๊ณ ์ž ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

๋”๋ฏธ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ™์†Œ 20๋งŒ๊ฐœ, ์˜ˆ์•ฝ 100๋งŒ๊ฐœ, ํšŒ์› 1๋งŒ๋ช…์„ ๋งŒ๋“ค๊ณ ์ž ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์ด ์ค‘, ์ˆ™์†Œ 20๋งŒ๊ฐœ๋ฅผ ๋งŒ๋“œ๋Š” ๊ณผ์ •์—์„œ ์ƒ๊ธด ์ผ์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.

 

20๋งŒ๊ฐœ ์ˆ™์†Œ ๋ฐ์ดํ„ฐ๋ฅผ Java ์ฝ”๋“œ๋กœ ์ˆ™์†Œ 1๊ฐœ๋งˆ๋‹ค INSERT INTO ์ฟผ๋ฆฌ๋ฅผ DB์— ๋‚ ๋ ธ๋”๋‹ˆ DB connection timeout ๋ฌธ์ œ๋ฅผ ๋งˆ์ฃผํ–ˆ์Šต๋‹ˆ๋‹ค.

 

- ๊ณ ๋ คํ•œ ๋ฐฉ์•ˆ

  • MySQL์˜ ๋ ˆ์ฝ”๋“œ๋Š” ํ…Œ์ด๋ธ” ๋‹จ์œ„์˜ ํŒŒ์ผ๋กœ ์ €์žฅ๋œ๋‹ค๋Š” ์ ์— ์ฐฉ์•ˆํ•œ csvํŒŒ์ผ ์‚ฌ์šฉ
  • ๋Œ€๋Ÿ‰ ์‚ฝ์ž…์— ํŠนํ™”๋œ ๊ธฐ์ˆ ์ธ Spring Batch

 

- 2๊ฐ€์ง€ ์ด์œ ๋กœ csvํŒŒ์ผ์„ ์ด์šฉํ•˜๊ธธ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ํ”„๋กœ์ ํŠธ ๋‚จ์€ 1์ฃผ ๋™์•ˆ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด์•ผ๋œ๋‹ค๋Š” ์ 
  • ๋”๋ฏธ ๋ฐ์ดํ„ฐ๋Š” 1ํšŒ์„ฑ ์ž‘์—…์ด๋ผ๋Š” ์ 

 

์•„๋ž˜ ๋‚ด์šฉ์€ Docker ๋กœ ๋„์šด MySQL ์„œ๋ฒ„์— CSVํŒŒ์ผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒŒํฌ Insert ํ•˜๋Š” ๊ณผ์ •์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.

โญ๋ฌธ์ œ ํ•ด๊ฒฐ ๊ณผ์ •

๊ฐœ๋ฐœ ํ™˜๊ฒฝ
๊ฐ€์ƒํ™˜๊ฒฝOS : WSL2
Docker Engine : 26.1.1
JPA : 3.x
Mysql : 8.0
Spring boot : 3.x
JDK : 17
IDE : IntelliJ ultimate

์ธํ…”๋ฆฌ์ œ์ด์—์„œ csvํŒŒ์ผ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•

๋จผ์ €, ์ž๋ฐ”๋กœ csv ํŒŒ์ผ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ build.gradle ์— ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

implementation 'org.apache.commons:commons-csv:1.11.0'

 

 

csvํŒŒ์ผ์„ ๋งŒ๋“ค๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ณ„๋„์˜ api ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ ์‹œํ‚จ ๋’ค ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ํ•ด๋‹น api ๋ฅผ ๋ฐ›๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ,

์ปจํŠธ๋กค๋Ÿฌ์™€ ๋ณ„๋„์˜ api ๋ฅผ ๋งŒ๋“ค๊ธฐ ๋ณด๋‹ค๋Š” @PostConstruct ๋ฅผ ์ด์šฉํ•ด์„œ ๋”๋ฏธ ๋ฐ์ดํ„ฐ ๋งŒ๋“œ๋Š” ๊ณผ์ •์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

 

@PostConstruct ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์‹œ์ ์€ ์Šคํ”„๋ง์ปจํ…์ŠคํŠธ๊ฐ€ ๋นˆ์„ ์ƒ์„ฑํ•˜๊ณ , ๋นˆ๋“ค๊ฐ„์˜ ์˜์กด์„ฑ ์ฃผ์ž…์ด ๋๋‚œ ์ดํ›„์— ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๊ธฐ์—, DummyStayService ์œ„์— @Component ๋ฅผ ๋ถ™์—ฌ ํ•ด๋‹น ํด๋ž˜์Šค๊ฐ€ ์Šคํ”„๋ง์ปจํ…์ŠคํŠธ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๊ฒŒ ํ•˜์˜€๊ณ ,

2๊ฐœ์˜ stay, member ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ, ์˜์กด์„ฑ ์ฃผ์ž…์ด ๋๋‚œ ํ›„์— ์‹คํ–‰๋  ๋ฉ”์„œ๋“œ์ธ init() ์œ„์— @PostConstruct ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์—ฌ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 

์•„๋ž˜ ์ฝ”๋“œ๋Š” ์ „์ฒด ์ฝ”๋“œ์ด๋ฉฐ, csvํŒŒ์ผ์„ ๋งŒ๋“œ๋Š” ๋ฉ”์„œ๋“œ๋Š” writeStaysToCSV  ์ž…๋‹ˆ๋‹ค.

  • ํŒŒ์ผ ์ž…์ถœ๋ ฅ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— try-with resource ๊ตฌ๋ฌธ์œผ๋กœ ์ž๋™์œผ๋กœ ํŒŒ์ผ ๋ฆฌ์†Œ์Šค๋ฅผ close ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. 
  • withHeader ๋ฅผ ํ†ตํ•ด csvํŒŒ์ผ์˜ ํ–‰์„ ์ง€์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
  • printer.printRecord ์—๋Š” csvํŒŒ์ผ ํ–‰์— ๋งž์ถฐ ๋“ค์–ด๊ฐˆ ๋ ˆ์ฝ”๋“œ(๋ฐ์ดํ„ฐ)๋ฅผ ๋„ฃ์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  • @lon, @lat ์€ MySQL ์—์„œ ๊ณต๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์›ํ•ด์ฃผ๋Š” POINT ํƒ€์ž…์œผ๋กœ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ์ง€์ •๋œ ํ‘œํ˜„์ž…๋‹ˆ๋‹ค.
    • POINT ํƒ€์ž…์€ X(๊ฒฝ๋„)์™€ Y(์œ„๋„) ๋‘ ๊ฐœ์˜ ์ขŒํ‘œ ๊ฐ’์„ ํฌํ•จํ•˜๋ฉฐ, POINT(x, y) ํ˜•์‹์ž…๋‹ˆ๋‹ค.
    • csvํŒŒ์ผ์—๋Š” @lon ์ด๋ฆ„์œผ๋กœ ๊ฒฝ๋„, @lat ์ด๋ฆ„์œผ๋กœ ์œ„๋„๊ฐ€ ์ €์žฅ๋˜๋ฉฐ csvํŒŒ์ผ์ด MySQL ํ…Œ์ด๋ธ” ํŒŒ์ผ์— ์“ฐ์—ฌ์งˆ ๋•Œ, POINT ํƒ€์ž…์œผ๋กœ ์ €์žฅ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ „์ฒด ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

package com.airdnb.clone.dummy;

// custom import
import com.airdnb.clone.domain.member.entity.Member;
import com.airdnb.clone.domain.member.repository.MemberRepository;
import com.airdnb.clone.domain.stay.entity.Stay;
import com.airdnb.clone.domain.stay.repository.StayRepository;
import com.airdnb.clone.dummy.member.DummyMemberGenerator;
import com.airdnb.clone.dummy.stay.DummyStayGenerator;
---
import jakarta.annotation.PostConstruct;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class DummyStayService {

    @Autowired
    private StayRepository stayRepository;

    @Autowired
    private MemberRepository memberRepository;

    // ๋”๋ฏธ๋ฐ์ดํ„ฐ ๋งŒ๋“ค์ง€ ์•Š์„ ๋•Œ๋Š” ์ฃผ์„ ํ’€์ง€ ์•Š๊ธฐ
    @PostConstruct
    public void init() {
    	// 1๋งŒ๋ช…์˜ ํšŒ์›์„ ๋žœ๋ค์œผ๋กœ ์ƒ์„ฑ
        List<Member> members = IntStream.range(0, 10000)
                .mapToObj(i -> DummyMemberGenerator.generate())
                .collect(Collectors.toList());
                
        // ์ƒ์„ฑํ•œ ํšŒ์›์„ ๋ชจ๋‘ ์ €์žฅ
        memberRepository.saveAll(members);

        List<Member> allMembers = memberRepository.findAll();

        // ์ˆ™์†Œ๋ฅผ 20๋งŒ๊ฐœ ๋งŒ๋“ค ๊ฒƒ์ธ๋ฐ, ์ง€์—ญ์— ๋”ฐ๋ผ ์ˆ™์†Œ ๊ฐœ์ˆ˜๋ฅผ custom ํ•˜๊ฒŒ ์„ค์ •.
        List<Stay> stays = IntStream.range(0, 200000)
                .mapToObj(i -> {
                    if (0 <= i && i <= 60000) {
                        return DummyStayGenerator.generateJeju();
                    }
                    else if (60001 <= i && i <= 100000) {
                        return DummyStayGenerator.generateBusan();
                    }
                    else if (100001 <= i && i <= 140000) {
                        return DummyStayGenerator.generateGangwon();
                    }
                    return DummyStayGenerator.generate();
                })
                .collect(Collectors.toList());

        // ๋งŒ๋“ค์–ด์ง„ ํšŒ์›๊ณผ ์ˆ™์†Œ๋ฐ์ดํ„ฐ๋ฅผ stays.csv ๋ž€ ์ด๋ฆ„์„ ๊ฐ€์ง„ csvํŒŒ์ผ์— ๋„ฃ๋Š” ์ž‘์—…
        try {
            writeStaysToCSV(allMembers, stays, "stays.csv");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void writeStaysToCSV(List<Member> allMembers, List<Stay> stays, String fileName) throws IOException {
        try (FileWriter out = new FileWriter(fileName);
             CSVPrinter printer = new CSVPrinter(out, CSVFormat.DEFAULT
                     // csvํŒŒ์ผ์˜ ์ฒซ ํ–‰์˜ ์ด๋ฆ„์„ ์ง€์ •
                     .withHeader("BATH_COUNT", "BEDROOM_COUNT", "BED_COUNT", "CHECK_IN_TIME"
                             , "CHECK_OUT_TIME", "GUEST_COUNT", "CLEANING_FEE", "HOST_ID"
                             , "PER_NIGHT", "ALIAS", "DESCRIPTION", "@lat", "@lon"))) {

            // count ๋Š” ํšŒ์› ๋‹น ์ˆ™์†Œ๋ฅผ 2๊ฐœ ๊ฐ€์ง€๋„๋ก ํ•˜๊ธฐ ์œ„ํ•จ.
            int count = 0;
            
            // ์ˆ™์†Œ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ csvํŒŒ์ผ ํ–‰์— ๋งž๊ฒŒ ์ˆ™์†Œ ๋ฐ์ดํ„ฐ ์“ฐ๊ธฐ
            for (Stay stay : stays) {
                printer.printRecord(
                    ์ˆ™์†Œ ์ปฌ๋Ÿผ์— ๋งž๊ฒŒ ๋ฐ์ดํ„ฐ ๊ฐ€๊ณต..., stay.getPoint().getY(), stay.getPoint().getX());
                if (count == 9999) {
                    count = 0;
                }
            }
        }
    }
}

 

์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ ํ›„, ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜๋ฉด csvํŒŒ์ผ์ด ํ”„๋กœ์ ํŠธ์˜ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ์— ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

csv ํŒŒ์ผ์„ ์—ด์–ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋”๋ฏธ ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Docker ๋กœ ๋„์šด MySQL ๋กœ csvํŒŒ์ผ ์˜ฎ๊ธฐ๊ธฐ

์ด์ œ ์ด csvํŒŒ์ผ์„ docker ๋กœ ๋„์šด MySQL ์„œ๋ฒ„๋กœ ํŒŒ์ผ์„ ์ „์†กํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

๋จผ์ €, wsl2 ์— ์ ‘์†์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.(์œˆ๋„์šฐ ๊ธฐ์ค€)

 

stays.csv ํŒŒ์ผ์„ conta ๋ผ๋Š” docker ์ปจํ…Œ์ด๋„ˆ์˜ /var/lib/mysql-files ๋ž€ ๊ฒฝ๋กœ์˜ stays.csv ์ด๋ฆ„์œผ๋กœ ํŒŒ์ผ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

docker cp ๋Š” Docker ์ปจํ…Œ์ด๋„ˆ์™€ ํ˜ธ์ŠคํŠธ ๊ฐ„์— ํŒŒ์ผ์„ ๋ณต์‚ฌํ•˜๋Š” Docker ๋ช…๋ น์–ด์ž…๋‹ˆ๋‹ค.

docker cp /mnt/c/Users/user/stays.csv conta:/var/lib/mysql-files/stays.csv
docker cp         [csvํŒŒ์ผ ๊ฒฝ๋กœ]       [์ปจํ…Œ์ด๋„ˆ ์ด๋ฆ„]:/var/lib/mysql-files/[csvํŒŒ์ผ ์ด๋ฆ„]

 

์ด์ œ, docker ๋ช…๋ น์–ด๋กœ MySQL ์— ์ ‘์†ํ•ฉ๋‹ˆ๋‹ค.

docker exec -it [mysql์ด ์žˆ๋Š” container์ด๋ฆ„] mysql -u root -p
docker exec -it conta mysql -u root -p

์ €๋Š” root ๋ง๊ณ , team04 ๋ผ๋Š” ์‚ฌ์šฉ์ž๋กœ ์ ‘์†ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

docker์— ์žˆ๋Š” mysql์— ์ ‘์† ํ›„, ์‚ฌ์šฉํ•  DB๋ฅผ ์„ ํƒ(์„ ํƒํ•  DB๊ฐ€ ์—†์œผ๋ฉด ํ•˜๋‚˜ ๋งŒ๋“ญ๋‹ˆ๋‹ค)ํ•ฉ๋‹ˆ๋‹ค.

use airdnb_db;
use [์‚ฌ์šฉํ•  DB ์ด๋ฆ„];

 

์„ ํƒํ•œ DB์— csv๋กœ ๋„ฃ์„ ๋ฐ์ดํ„ฐ์˜ ์ปฌ๋Ÿผ์ด๋ฆ„๊ณผ ํƒ€์ž…์— ๋งž๊ฒŒ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค.

์ €๋Š” ์ธํ…”๋ฆฌ์ œ์ด์—์„œ JPA์˜ ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ๊ตฌํ˜„์ฒด์˜ ๊ธฐ๋Šฅ์ธ ddl-auto:create ๋กœ ์ƒ์„ฑํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

โญ MySQL ์„œ๋ฒ„์— ์žˆ๋Š” csvํŒŒ์ผ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด ํ…Œ์ด๋ธ” ํŒŒ์ผ์— ์‚ฝ์ž…

LOAD DATA INFILE '/var/lib/mysql-files/stays.csv' // ํ•ด๋‹น ๊ฒฝ๋กœ์— ์žˆ๋Š” csvํŒŒ์ผ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.
INTO TABLE STAY                               // ๋กœ๋“œ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•  ํ…Œ์ด๋ธ”์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
FIELDS TERMINATED BY ','                      // csvํŒŒ์ผ์˜ ๊ฐ ์—ด์ด ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋˜์–ด ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
ENCLOSED BY '"'                               // csvํŒŒ์ผ์˜ ๊ฐ ์—ด ๊ฐ’์ด ํฐ๋”ฐ์˜ดํ‘œ๋กœ ๊ฐ์‹ธ์ ธ ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
LINES TERMINATED BY '\n'                      // csvํŒŒ์ผ์—์„œ ๊ฐ ํ–‰์ด ์ค„ ๋ฐ”๊ฟˆ์œผ๋กœ ๊ตฌ๋ถ„๋˜์–ด ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
IGNORE 1 ROWS                                 // ์ฒซ ๋ฒˆ์งธ ํ–‰(์ผ๋ฐ˜์ ์œผ๋กœ ํ—ค๋” ํ–‰)์„ ๋ฌด์‹œํ•˜๋„๋ก ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
(BATH_COUNT, BEDROOM_COUNT, BED_COUNT, CHECK_IN_TIME, CHECK_OUT_TIME, GUEST_COUNT, CLEANING_FEE, HOST_ID, PER_NIGHT, ALIAS, DESCRIPTION, @lat, @lon)
// csvํŒŒ์ผ์˜ ๊ฐ ์—ด์„ ํ…Œ์ด๋ธ”์˜ ํ•ด๋‹น ์—ด์— ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.
// csvํŒŒ์ผ์˜ ์—ด ์ˆœ์„œ์™€ ๋™์ผํ•˜๊ฒŒ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
// @lat, @lon์€ ํŒŒ์ผ์˜ ์œ„๋„์™€ ๊ฒฝ๋„ ๊ฐ’์„ ์ž„์‹œ ๋ณ€์ˆ˜๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
SET POINT = ST_GeomFromText(CONCAT('POINT(', @lat, ' ', @lon, ')'), 4326);
// POINT ์—ด์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
/ ST_GeomFromText ํ•จ์ˆ˜๋Š” ํ…์ŠคํŠธ ํ‘œํ˜„์„ ์ง€๋ฆฌ์  ์ขŒํ‘œ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
// CONCAT('POINT(', @lat, ' ', @lon, ')')๋Š” POINT(@lat, @lon) ํ˜•์‹์˜ ๋ฌธ์ž์—ด์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
// 4326์€ ์ขŒํ‘œ ์ฐธ์กฐ ์‹œ์Šคํ…œ(SRID)๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

โญ๊ฒฐ๊ณผ

์ด ๊ฒฐ๊ณผ๋กœ 20๋งŒ๊ฑด์˜ ๋ฐ์ดํ„ฐ๋ฅผ IDE์—์„œ ์ผ์ผ์ด Stream์œผ๋กœ ๋Œ๋ฉด์„œ Insert ํ•˜๋ฉด connection timeout ์ด ๋ฐœ์ƒํ–ˆ๋˜ ๋ฌธ์ œ๋ฅผ

csvํŒŒ์ผ๋กœ ๋ฒŒํฌ insert ํ•ด์„œ 7์ดˆ๋งŒ์— ํ•ด๊ฒฐํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

โญ๋งˆ์ฃผํ•œ ์—๋Ÿฌ ํ•ด๊ฒฐ ๊ณผ์ •์„ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค

ERROR 3948 (42000): Loading local data is disabled; this must be enabled on both the client and server sides
  • ๋กœ์ปฌ ๋ฐ์ดํ„ฐ ๋กœ๋“œ๋ฅผ ํ—ˆ์šฉํ•˜๋ฉด ๋ณด์•ˆ์ƒ ์œ„ํ—˜ํ•˜๊ธฐ์— MySQL ์—์„œ๋Š” ์ด ๊ธฐ๋Šฅ์„ ๊ธฐ๋ณธ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™” ํ•ด์ฃผ๊ธฐ ๋ณด๋‹ค๋Š” MySQL ํŒŒ์ผ์— ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ๊ณผ์ •์—์„œ ๋ช…๋ น์–ด๋ฅผ `LOAD DATA LOCAL INFILE` ์ด ์•„๋‹Œ `LOAD DATA INFILE` ๋กœ ํ•ฉ๋‹ˆ๋‹ค.
ERROR 1045 (28000): Access denied for user 'team04'@'%' (using password: YES) 
  • ์‚ฌ์šฉ์ž(team04)์—๊ฒŒ ์–ด๋–ค ํ˜ธ์ŠคํŠธ์—์„œ๋„ ์ ‘์†ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ถŒํ•œ์„ ์ค˜์•ผํ•ฉ๋‹ˆ๋‹ค.
  • mysql ์„ root ๊ณ„์ •์œผ๋กœ ์ ‘์†ํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ์ณ์„œ team04 ์—๊ฒŒ ๊ถŒํ•œ์„ ์ค๋‹ˆ๋‹ค.
GRANT FILE ON *.* TO 'team04'@'%';
FLUSH PRIVILEGES;
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
  • ์ €๋Š” /var/lib/mysql-files ๋กœ csvํŒŒ์ผ์„ ์˜ฎ๊ธฐ์ง€ ์•Š๊ณ , LOAD DATE INFILE ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค.
  • ์ด ์—๋Ÿฌ๋Š” MySQL ์„œ๋ฒ„๊ฐ€ --secure-file-priv ์˜ต์…˜์œผ๋กœ ์‹คํ–‰๋˜๊ณ  ์žˆ์–ด์„œ, ํ•ด๋‹น ๋ช…๋ น๋ฌธ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • --secure-file-priv ์˜ต์…˜์€ ๋ณด์•ˆ์„ ์œ„ํ•ด ๋„์ž…๋œ ๊ธฐ๋Šฅ์œผ๋กœ, MySQL ์„œ๋ฒ„์—์„œ LOAD DATA INFILE ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ ํ—ˆ์šฉ๋œ ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ๋ฅผ ์ œํ•œํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค

LOAD DATA INFILE ๋ช…๋ น์ด ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

mysql> SHOW VARIABLES LIKE 'secure_file_priv';
+------------------+-----------------------+
| Variable_name    | Value                 |
+------------------+-----------------------+
| secure_file_priv | /var/lib/mysql-files/ |
+------------------+-----------------------+

/var/lib/mysql-files ์—์„œ๋Š” LOAD DATA INFILE ๋ช…๋ น์ด ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ๋‚˜์˜ต๋‹ˆ๋‹ค.

docker cp ๋ช…๋ น์„ ์‚ฌ์šฉํ•ด์„œ csvํŒŒ์ผ์„ /var/lib/mysql-files/ ๋กœ ์˜ฎ๊ฒจ์ค๋‹ˆ๋‹ค.

ERROR 1366 (HY000): Incorrect integer value: 'Location' for column 'BATH_COUNT' at row 1
  • LOAD DATA INFILE ๋ช…๋ น์„ ์‹คํ–‰ ํ•  ๋•Œ, ์ปฌ๋Ÿผ ์ด๋ฆ„๊ณผ csvํŒŒ์ผ์˜ ํ–‰ ์ˆœ์„œ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์„ ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • csvํŒŒ์ผ ํ–‰ ์ˆœ์„œ์— ๋งž๊ฒŒ (BATH_COUNT, ... @lan, @lon) ์„ ์ ์–ด์ค๋‹ˆ๋‹ค.
ERROR 1416 (22003): Cannot get geometry object from data you send to the GEOMETRY field 
  • ๊ณต๊ฐ„๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ORM ์—๋„ ๊ณต๊ฐ„ ๋ฐ์ดํ„ฐ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ €๋Š” querydsl ๊ณผ JPA ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ๊ตฌํ˜„์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
// ์œ„๋„ ๊ฒฝ๋„
implementation 'org.hibernate:hibernate-spatial:6.5.2.Final'
implementation 'com.querydsl:querydsl-spatial:5.1.0'
ERROR 3643 (HY000): The SRID of the geometry does not match the SRID of the column 'POINT'. The SRID of the geometry is 0, but the SRID of the column is 4326. Consider changing the SRID of the geometry or the SRID property of the column.
  • SET POINT = ST_GeomFromText(CONCAT('POINT(', @lat, ' ', @lon, ')'), 4326); ์—์„œ 4326์ด ์—†์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค.
  • 4326์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.
ERROR 3617 (22S03): Latitude 126.543171 is out of range in function st_geomfromtext. It must be within [-90.000000, 90.000000]
  • ์œ„๋„ ๊ฒฝ๋„ ์ปฌ๋Ÿผ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • Java ์—์„œ Point.getY() ๋Š” @lat (์œ„๋„)์— ํ•ด๋‹น๋˜๊ณ , Point.getX() ๋Š” @lon (๊ฒฝ๋„)์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.
ERROR 3037 (22023): Invalid GIS data provided to function st_geomfromtext.
  • ST_GeomFromText(CONCAT('POINT(', @lat, ' ', @lon, ')') ๊ตฌ๋ฌธ์ด ์ž˜ ์ž‘์„ฑ ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ST_GeomFromText() ํ•จ์ˆ˜์— ์ „๋‹ฌํ•  ๋ฌธ์ž์—ด์ด ์˜ฌ๋ฐ”๋ฅธ ํ˜•์‹๊ณผ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, POINT(1 2) ์™€ ๊ฐ™์€ ํ˜•์‹๊ณผ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

โญํšŒ๊ณ 

์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๋‹ค๋Ÿ‰์˜ ๋”๋ฏธ ๋ฐ์ดํ„ฐ๋ฅผ csvํŒŒ์ผ๋กœ ๋งŒ๋“ค ๋•Œ,

csvํŒŒ์ผ์˜ ์œ„๋„ ๊ฒฝ๋„ ๊ฐ’์„ POINT ํƒ€์ž…์— ๋„ฃ๊ธฐ ์œ„ํ•ด ์–ด๋–ป๊ฒŒ ์ฟผ๋ฆฌ๋ฅผ ์งœ์•ผ ํ•˜๋Š”์ง€๊ฐ€ ๊ฐ€์žฅ ์–ด๋ ค์› ๊ณ , ์ด๋ฅผ ๊ณต๊ฐ„๋ฐ์ดํ„ฐ์™€ ๊ณต๊ฐ„ ํ•จ์ˆ˜๋ฅผ ํ•™์Šตํ•˜๋ฉฐ ๊ทน๋ณตํ–ˆ์Šต๋‹ˆ๋‹ค.

 

csvํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋ฉฐ ์ƒ๊ฐํ•œ ๋‹จ์ ์ž…๋‹ˆ๋‹ค.

  • ๋งŒ์•ฝ, enum ํƒ€์ž…์„ ๋„ฃ๊ณ  ์‹ถ๋‹ค๋ฉด? ๋‹ค๋ฅธ ๊ณต๊ฐ„ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ๋„ฃ๊ณ  ์‹ถ๋‹ค๋ฉด? MySQL ์ด ์•„๋‹Œ ๋‹ค๋ฅธ DBMS ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด?  ์ฆ‰, MySQL์ด ์ง€์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž…์— ๋”ฐ๋ผ ์ž‘์„ฑํ•ด์•ผ ํ•  ์ฟผ๋ฆฌ๊ฐ€ ๋‹ฌ๋ผ์ง€๊ธฐ ๋•Œ๋ฌธ์— ์ž๋™ํ™” ์ž‘์—…์ด ์•ˆ๋ฉ๋‹ˆ๋‹ค.
  • ์ œ ๋ฐฉ๋ฒ•์€ PostConstruct ์˜ csvํŒŒ์ผ์„ ๋งŒ๋“œ๋Š” ์ž‘์—… ๋•Œ๋ฌธ์— ์Šคํ”„๋ง ์„œ๋ฒ„๊ฐ€ ๋Šฆ๊ฒŒ ๋œน๋‹ˆ๋‹ค.
    • ๊ทธ๋ž˜์„œ, csvํŒŒ์ผ์„ ๋งŒ๋“ค์ง€ ์•Š๊ธฐ ์œ„ํ•ด ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์ฃผ์„์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค(1ํšŒ์šฉ์ด๊ธฐ ๋•Œ๋ฌธ์—)

๊ทธ๋ž˜์„œ,

๋‹ค์Œ ๋ฒˆ์—๋Š” Spring Batch ๋ฅผ ํ•™์Šตํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค

๋•Œ๋กœ๋Š”, ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด varchar ๋‚˜ Integer ๊ฐ™์€ ๋‹จ์ˆœํ•œ ํƒ€์ž…์ผ ๋•Œ ์ด ๊ฒฝํ—˜์„ ๋ฐ”ํƒ•์œผ๋กœ ๋‹ค์‹œ ์‹œ๋„ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ, MySQL์˜ ๊ณต๊ฐ„ ๋ฐ์ดํ„ฐ์™€ ๊ณต๊ฐ„ ํ•จ์ˆ˜์— ๋Œ€ํ•ด ํ•™์Šตํ•  ์ˆ˜ ์žˆ๋˜ ์‹œ๊ฐ„๊ณผ '๋ฌธ์ œ ํ•ด๊ฒฐ์ด๋ผ๋ฉด ์–ด๋–ป๊ฒŒ์„œ๋“  ํ•˜๊ณ  ์‹ถ๋‹ค๋Š” ์ง‘๋…์ด ์žˆ๋‹ค'๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋œ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…์ด์—ˆ์Šต๋‹ˆ๋‹ค.