2025-08-06

1. 오늘 한 일 (What I Did)

1-1. Docker로 MySQL 설치하고 실행하기

1-1-1. 명령어로 MySQL 실행

docker run --name mysql -e MYSQL_ROOT_PASSWORD=1234 -d -p 3306:3306 mysql:latest

이 명령어 하나로 MySQL이 내 컴퓨터에 설치되고 실행됐다!

  • --name mysql: 컨테이너 이름을 'mysql'로 지정
  • -e MYSQL_ROOT_PASSWORD=1234: 관리자 비밀번호를 1234로 설정
  • -p 3306:3306: MySQL 기본 포트 연결
  • -d: 백그라운드에서 실행

1-1-2. Docker Desktop GUI와 터미널 이름이 달라서 헷갈렸던 문제

  • Docker Desktop에서는: practice-hanbi로 보임
  • 터미널에서는: mysql로 보임
  • 해결: docker ps 명령어로 확인한 이름이 진짜! → mysql 사용/ 문제는 없었으나 정리하고 싶은 강박으로 컨테이너 삭제하고 다시 마듬 

1-1-3. MySQL에 접속하는 과정

# 1단계: Docker 컨테이너 안으로 들어가기
docker exec -it mysql bash

# 2단계: 이제 MySQL 접속하기
mysql -uroot -p
# 비밀번호: 1234

처음엔 맥 터미널에서 바로 mysql 명령어를 쳤다가 "command not found" 에러를 봤다. MySQL은 Docker 컨테이너 안에 있으니까 먼저 컨테이너로 들어가야 한다는 걸 배웠다!

1-1-4. docker-compose.yml 파일 만들기

긴 Docker 명령어를 매번 치기 귀찮으면 파일로 만들 수 있다. 

version: "3.8"
services:
  db:
    image: mysql:latest
    container_name: mysql
    restart: always
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: 1234
      TZ: Asia/Seoul
    volumes:
      - ./mysql:/var/lib/mysql  # 데이터 저장 위치
  • 파일 위치: 프로젝트 최상위 폴더 (package.json이랑 같은 위치)
  • 실행 방법: docker compose up -d

1-1-5. 데이터베이스와 사용자 만들기

-- 1. 데이터베이스 만들기
CREATE DATABASE todo_list_db;

-- 2. 새 사용자 만들기
CREATE USER 'hanbi'@'%' IDENTIFIED BY '1234';
-- 'hanbi': 사용자 이름
-- '%': 어디서든 접속 가능 (localhost만 하려면 'localhost')
-- '1234': 비밀번호

-- 3. 권한 주기
GRANT ALL PRIVILEGES ON todo_list_db.* TO 'hanbi'@'%';
-- todo_list_db의 모든 권한을 hanbi에게 줌

-- 4. 권한 적용
FLUSH PRIVILEGES;

1-2. 할일 관리 앱을 위한 테이블 5개 설계

이런 구조로 설계했다.

👤 User (사용자)
  └── 📁 Project (프로젝트)
       └── 📋 Board (칸반 보드: To Do, In Progress, Done)
            └── ✅ Task (할 일)
                 └── 📝 Sub_task (세부 할 일)

1-3. schema.sql 파일 작성하고 실행하기

프로젝트 폴더에 schema.sql 파일을 만들고 테이블 생성 코드를 작성했다.

실행 방법 3가지를 시도했다. 

  1. VS Code SQLTools에서 실행 → 연결 문제로 실패
  2. MySQL 안에서 복사-붙여넣기 → 성공!
  3. 터미널에서 파일 실행 → 이것도 성공!
 
docker exec -i mysql mysql -uhanbi -p1234 todo_list_db < schema.sql

 


2. 새로 이해한 것 (What I Learned)

2-1. Docker가 뭔지 이해했다

Docker = 내 컴퓨터 안의 작은 컴퓨터

  • 예전: MySQL을 내 맥에 직접 설치 → 지우기 어렵고 꼬임
  • 지금: Docker 컨테이너에 설치 → 필요없으면 컨테이너만 삭제하면 깔끔!

컨테이너 vs 이미지

  • 이미지 = 붕어빵 틀 (MySQL 설치 파일)
  • 컨테이너 = 붕어빵 (실제로 실행 중인 MySQL)

2-2. SQL 테이블 만드는 기본 문법

CREATE TABLE 테이블이름 (
    컬럼이름 데이터타입 제약조건,
    컬럼이름 데이터타입 제약조건,
    -- 마지막엔 콤마 없음!
);

 

2-3. 데이터 타입 종류와 언제 쓰는지

숫자 타입

  • TINYINT: 아주 작은 숫자 (0~255) → 우선순위 같은 거
  • INT: 보통 숫자 (-21억~21억) → 순서, 개수
  • BIGINT: 엄청 큰 숫자 → ID값 (나중에 데이터 많아져도 OK)

문자 타입

  • VARCHAR(100): 최대 100자 → 이름, 제목
  • VARCHAR(255): 최대 255자 → 이메일, URL
  • TEXT: 아주 긴 글 → 본문, 설명

시간 타입

  • TIMESTAMP: 날짜+시간 → 언제 만들었는지, 언제 수정했는지

2-4. Primary Key와 Foreign Key 이해

Primary Key (PK) = 주민등록번호

id BIGINT AUTO_INCREMENT PRIMARY KEY
  • 각 행을 구분하는 고유 번호
  • 자동으로 1, 2, 3... 증가
  • 절대 중복 안 됨, 비어있을 수 없음

Foreign Key (FK) = 다른 테이블 가리키는 화살표

user_id BIGINT,
FOREIGN KEY (user_id) REFERENCES user(id)
  • 예: project 테이블의 user_id = 1 → user 테이블의 id = 1인 사람 것
  • 없는 번호는 못 넣음 (user 테이블에 1번이 없으면 에러)

2-5. 테이블 삭제 순서가 중요한 이유!

잘못된 순서 (에러 발생)

DROP TABLE user;  -- ❌ "project가 user를 참조 중이라 못 지워!"

올바른 순서 (자식부터 삭제)

DROP TABLE sub_task;  -- 5층 (제일 아래)
DROP TABLE task;      -- 4층
DROP TABLE board;     -- 3층  
DROP TABLE project;   -- 2층
DROP TABLE user;      -- 1층 (제일 위)

레고 탑 부수기랑 똑같다! 위에서부터 하나씩 빼야 안 무너진다.

2-6. 왜 모든 테이블에 user_id가 있을까?

이론적으로는: project만 user_id 가지고, 나머지는 project 통해서 찾으면 됨

실무에서는:

-- user_id 없으면 (느림 - JOIN 3번!)
SELECT * FROM task t
JOIN board b ON t.board_id = b.id
JOIN project p ON b.project_id = p.id
WHERE p.user_id = 1;

-- user_id 있으면 (빠름 - JOIN 없이!)
SELECT * FROM task WHERE user_id = 1;

"한비가 만든 모든 할일 보여줘" 같은 질문에 바로 답할 수 있다!

2-7. CASCADE 옵션 이해하기

ON DELETE CASCADE = 연쇄 삭제

FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE
  • 사용자 삭제 → 그 사람의 프로젝트도 자동 삭제
  • 편하지만 위험할 수 있음

ON DELETE SET NULL = NULL로 바꾸기

FOREIGN KEY (board_id) REFERENCES board(id) ON DELETE SET NULL
  • 보드 삭제 → 태스크는 남지만 board_id가 NULL이 됨
  • "보드 없는 태스크"가 됨 (백로그 상태)

3. 실수했던 부분들 (What I Struggled With)

3-1. 콤마(,) 때문에 고생한 이야기

실수 1: 마지막에 콤마 넣음

-- 틀린 코드
CREATE TABLE user (
    id BIGINT PRIMARY KEY,
    name VARCHAR(100),  -- 마지막인데 콤마 있음!
);

실수 2: 필요한 곳에 콤마 빼먹음

-- 틀린 코드
update_at TIMESTAMP  -- 콤마 없음!
CONSTRAINT ...  -- 에러 발생!

실수 3: CONSTRAINT 뒤에 콤마

-- 틀린 코드
CONSTRAINT user_project_fk FOREIGN KEY ...,  -- 마지막인데 콤마!
);

콤마 규칙 정리

  • 테이블 안에서 마지막 빼고 다 콤마!
  • 닫는 괄호 ) 앞에는 절대 콤마 없음!
  • 헷갈리면 마지막 줄 확인!

3-2. CONSTRAINT 이름 중복 문제

-- 에러: 같은 이름을 여러 번 사용
board 테이블: CONSTRAINT user_project_id_fk ...
task 테이블: CONSTRAINT user_project_id_fk ...  -- "이미 있는 이름!"

해결: 각자 다른 이름 사용

  • project 테이블: user_project_id_fk
  • board 테이블: user_board_id_fk
  • task 테이블: user_task_id_fk

3-4. Foreign Key 참조 실수

-- 틀린 코드 (task 테이블에서)
FOREIGN KEY (board_id) REFERENCES task(id)  -- task? 아니야!

-- 맞는 코드
FOREIGN KEY (board_id) REFERENCES board(id)  -- board가 맞아!

board_id는 board 테이블을 가리켜야 하는데 task를 가리키게 써서 에러!

3-5. 오타들

  • oder_no → order_no (order 스펠링)
  • lowlest → lowest (최하위 스펠링)
  • create_at 뒤에서 줄바꿈해서 문법 에러

3-6. VS Code 연결 실패

SQLTools 연결할 때 고급 설정 건드렸다가 에러:

  • Authentication Protocol: default → 그냥 비워둠
  • SSL: Enabled → Disabled로 변경

교훈: 모르는 설정은 건드리지 말자!

'TIL' 카테고리의 다른 글

2025-08-10 NestJS UsersService CRUD 구현 및 DTO 작성  (2) 2025.08.11
2025-08-09 NestJS + TypeORM DB 연동  (4) 2025.08.10
2025-08-03  (10) 2025.08.03
2025-07-31  (5) 2025.07.31
2025-07-30  (4) 2025.07.31