favicon

Jayden { do: smite }

230221(화)

🎄 성장일지 3.1

행복한 이기주의자(웨인 다이어)의 내용에 자극받아 시작하는 소박한 성장기록

살아있는 꽃과 죽은 꽃은 어떻게 구별하는가?<br/> 성장하고 있는 것이 살아 있는 것이다.<br/> 생명의 유일한 증거는 성장이다!

🌳 키워드 (1.0)<br/> 최대한 간단하게 정리, 추후에 보면서 스스로 설명<br/> 🍉 경험 위주로 (2.0)<br/> 단순 정보를 전달하기보다 무엇을 배웠고 어떻게 해결했는지 짧고 간단하게 작성<br/> ❄️ 정해진 템플릿에 맞춰서 (3.0)<br/> 키워드, 경험 모두 좋다. 다만 매일 작성하기로 마음 먹은만큼 핵심만 간결하게 정리할 수 있게 템플릿을 작성 (3.1) 230102부터 시작되는 학습에 관한 내용 추가

🔑 오늘의 키워드

도커로 mysql 컨테이너 띄우고 ts로 간단하게 연결하는 과정 복기

  1. 먼저 docker를 웹에서 다운로드 받는다.(본인의 OS에 맞게 잘 받아야한다.)
  • 도커 버전 확인

    docker -v
  1. docker를 통해 mysql 이미지를 가져와서 컨테이너를 띄운다. 이 때, 원하는 환경변수를 설정하는 건 덤이다!
docker run -d -p 3307:3306 --platform linux/amd64 -e MYSQL_ROOT_PASSWORD=1116 --name mysql-container mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
  • 3307포트로 root 비번은 1116인 mysql-container라는 이름을 가진 5.7 버전의 mysql 컨테이너를 띄운다. 이 때, character-set-server와 collation-server은 각각 utf8mb4로 설정한다.(한글 및 이모지 사용하기 위해)
  1. 실행 중인 컨테이너에 명령어를 실행할 수 있게 한다.(bash 사용)
docker exec -it mysql-container bash
  1. 루트 권한으로 mysql 서버(?) 혹은 컨테이너에 접속한다.
mysql -u root -p
  • 그러면 아까 위에서 설정한 root의 비밀번호를 입력하고 엔터를 입력한다.
  1. Database를 생성한다.
CREATE DATABASE dbname;
  1. 생성한 Database를 선택한다.
USE dbname;
  1. 이제 데이터베이스에 원하는 형태의 테이블을 만들어준다.
  • NOT NULL, PRIMARY KEY, FOREIGN KEY, UNIQUE 등의 제약 조건을 할당해줄 수 있다.
CREATE TABLE tablename (field1 field1-type PRIMARY KEY, field2 field2-type NOT NULL);
  1. root 권한은 예상치 못한 위험을 초래할 수 있으므로, 새로운 User를 만들고 권한을 할당해준다.
  • 예제는 모든 권한을 넘겨준 것이다.

    CREATE USER 'userID'@'%' identified by 'userpassword'; FLUSH PRIVILEGES; GRANT ALL PRIVILEGES ON dbname.* to userID@'%';
  1. mysql에서 exit하고 위에 지정해준 User로 접속한다.(위에서 지정한 패스워드로!)
mysql -u userID -p

여기까지가 아주 기초적인 과정이다! docker를 통해 mysql을 갖고 있는 컨테이너를 띄우고 그 안에서 마치 다른 서버에 database를 두는 것처럼 사용할 수 있다.<br/> 그럼 이제 로컬에서 간단하게 js 혹은 ts 코드로 mysql 라이브러리를 다운받아, 통신하듯이 사용할 수 있다.(위에 키워드 정리 중 MySQL 키워드의 예시처럼!)

Bulk Insert

  • db에 데이터를 insert할 때, insert 쿼리를 계속 날리면 쿼리 오픈과 클로즈에도 또 수많은 작업들이 발생한다.
  • 그래서 그런 과정을 좀 한번에 처리하고 우리가 원하는 아주 많은 데이터를 한번에 뙇 하고 넣는 게 Bulk Insert이다.

예제) 아래와 같은 느낌으로 전달한다.

// 이 때, `dataGenerator.allData`의 타입은 {nickname: string, money: number, last_visit: Date}[] 형태이다. // 해서 map으로 각 요소들을 배열 형태로 만들어주고 그 요소들을 또 한번 배열에 감싸서 전달해야한다. connection.query( 'INSERT INTO user_log (nickname, money, last_visit) VALUES ?', [ dataGenerator.allData.map((item) => [ item.nickname, item.money, item.last_visit, ]), ], (err: QueryError, results: RowDataPacket) => { if (err) { console.error(err); } else { console.log('완료되었습니다.'); } }, );

이 때, 한번에 너무 많은 데이터를 INSERT하게 되면 에러가 발생한다.

SQL 오류(1153): Got a packet bigger than 'max_allowed_packet' bytes

이를 해결하기 위해, mysql의 전송 packet 용량을 늘려주는 쿼리를 쓴다.(기본적으로 4MB)

SET GLOBAL max_allowed_packet=1000000000; SET GLOBAL net_buffer_length=1000000;

또한, INSERT 시 발생하는 transaction(트랜잭션)을 생략하기 위해 아래의 쿼리를 실행한다.(그러면 데이터 추가 속도가 빨라진다.)

SET autocommit = 1;

말그대로 INSERT 시에도 commit(데이터베이스에 방금 한 쿼리를 반영하겠다는 뜻)를 자동으로 해준다.

참고

📝 요약 및 하루 간단 회고

오늘은 정말 다양한 에러를 만났다. bulk insert 중 mysql 패킷 제한 오류, primary key 중복 오류 이외에도 잡다한 docker 환경변수 설정 오류까지...<br/> 그래도 확실히 오류가 나니까 구글링하기도 좋고 해결하기 너무 좋다. 보자마자 스트레스 받긴 하지만 해결하고보면 이정표같은 고마운 역할을 한다. 제품 개발 시에 테스트 코드를 왜 작성하고 왜 error, 예외 처리를 하는지 알 것 같다.

오늘의 잘한 점

  • 미션 구현 완료 및 개념 정리 정말 열심히 함!!!

오늘의 아쉬운 점

  • (추가 미션) data insert하는 과정을 시각적으로 progress bar 만드는 부분...
  • 뭔가 비동기적으로 insert할 때마다 console.log로 점점 길어지게 만들어주면 될 것 같다.(그렇게 어렵진 않을지도..?)
  • 근데 아마 내 코드는 bulk insert에서 bulk 단위를 커스텀하게 나누지 않아서, 이 부분을 분할하고
  • 계속 SELECT COUNT(*) 로 갯수 가져오면서 전체 데이터 수에 대비해 %로 log를 찍는 방식으로 해야할듯하다.
  • 아! 추가로 TypeORM을 써보고 싶었는데, 다음에 써보기로 한 점... 아쉽다! 뭔가 쿼리문을 ts 객체로 편하게 작성할 수 있게 해주는 거 같은데..!
  • 다음에 꼭 써봐야지
undefined

Copyright 2023. all rights reserved by Jayden