01 · OVERVIEW

개요

학생 프로젝트 진행 현황을 관리하는 시스템에서 신규 데이터를 등록할 때 MySQL 오류가 발생했습니다. 애플리케이션 로직에서는 ID가 자동으로 생성될 것으로 예상했지만 실제 스키마는 그 가정과 일치하지 않았습니다.

02 · PROBLEM

문제 상황

학생 데이터를 INSERT하는 과정에서 id 컬럼에 기본값이 없다는 오류가 발생하며 등록이 실패했습니다.

Field 'id' doesn't have a default value
03 · IMPACT

영향 범위

기존 행을 읽는 화면은 동작했지만 신규 학생·프로젝트 등록 경로가 막혔습니다. 즉 전체 데이터베이스 장애가 아니라 쓰기 경로의 스키마 계약 위반이었습니다.

영향: 신규 INSERT 실패. 비영향: 기존 데이터 조회. 데이터 유실이나 기존 행 삭제는 확인되지 않았습니다.
04 · EVIDENCE

확인된 사실

  • 오류 문자열은 MySQL이 id 값을 요구하고 있음을 가리켰습니다.
  • INSERT 쿼리는 ID 자동 생성을 전제로 id를 전달하지 않았습니다.
  • 요청의 업무 데이터는 들어왔고 조회 연결도 정상이라 연결 장애 가능성은 낮았습니다.
  • 실제 테이블의 id 컬럼에는 당시 AUTO_INCREMENT가 없었습니다.
05 · HYPOTHESIS

가설을 오류 계층별로 나눴습니다

  • 요청 계층: 필수 입력이나 값이 빠졌는가
  • 쿼리 계층: 컬럼 목록과 바인딩 값이 어긋났는가
  • 애플리케이션 계층: undefined가 전달됐는가
  • 스키마 계층: 기본키가 자동 생성되도록 정의됐는가
06 · DIAGNOSIS

진단 과정

  1. 실패한 INSERT의 컬럼 목록을 확인했습니다.
  2. 요청 본문과 바인딩되는 값을 비교했습니다.
  3. 조회 쿼리가 동작하는지 확인해 DB 연결 문제를 분리했습니다.
  4. DESCRIBE로 실행 중인 DB의 실제 스키마를 확인했습니다.
  5. idExtraauto_increment가 없음을 확인했습니다.
DESCRIBE student_project;

-- 확인 기준
-- Key   : PRI
-- Extra : auto_increment
07 · ROOT CAUSE

실제 원인

애플리케이션은 데이터베이스가 숫자 ID를 생성한다고 가정했지만, 당시 실제 테이블은 그 계약을 구현하지 않았습니다. 조회 코드가 정상이라는 사실과 별개로, 쓰기 코드와 배포된 스키마가 서로 다른 상태였습니다.

08 · DECISION

대안을 비교했습니다

애플리케이션에서 ID 계산동시 INSERT에서 충돌 위험이 생김
임시 기본값 지정고유성과 참조 관계를 보장하지 못함
운영 DB만 ALTER신규 환경에서 같은 문제가 재발함
스키마와 초기화 SQL 정렬DB가 ID 생성 책임을 갖고 환경 간 차이를 줄임
09 · ACTION

선택한 조치

운영 테이블의 기본키를 수정하고, 애플리케이션은 ID를 직접 만들지 않도록 유지했습니다. 같은 정의를 저장소의 schema.sql과 런타임 테이블 보장 코드에도 반영했습니다.

수정 전
id INT NOT NULL
수정 후
id INT AUTO_INCREMENT
  PRIMARY KEY
현재 공개 저장소의 student_project, project_comment, project_view_event 숫자 키가 같은 패턴을 사용합니다.
10 · VALIDATION

검증 기준

  1. ID를 제외한 업무 컬럼만으로 INSERT가 성공해야 합니다.
  2. 생성된 행에 중복되지 않는 숫자 ID가 있어야 합니다.
  3. 생성 ID로 다시 조회할 수 있어야 합니다.
  4. 새 DB를 초기화해도 같은 스키마가 만들어져야 합니다.
  5. 외래키를 사용하는 댓글·조회 이벤트 테이블과 연결돼야 합니다.
11 · RESULT

결과

  • 신규 데이터 등록과 ID 자동 생성이 정상화됐습니다.
  • 애플리케이션이 임의의 ID를 계산할 필요가 없어졌습니다.
  • 생성 ID를 이후 조회와 하위 테이블의 외래키로 사용할 수 있습니다.
  • 공개 저장소의 초기화 스키마에도 같은 정의가 남아 있습니다.
현재 저장소 확인: student_project.id INT AUTO_INCREMENT PRIMARY KEY. 운영 DB의 과거 결과 수치는 보존되지 않아 성공 건수를 만들지 않았습니다.
12 · PREVENTION

재발 방지

  • 테이블 생성 SQL을 저장소에서 버전 관리합니다.
  • 쓰기 기능 배포 전 실제 DB 스키마와 코드를 함께 확인합니다.
  • 신규 환경에서 초기화 후 INSERT 연기 테스트를 수행합니다.
  • 스키마 변경이 늘어나면 순서가 있는 마이그레이션으로 전환합니다.
13 · LIMITS & NEXT

기록 한계와 다음 단계

원본 장애 시점의 DESCRIBE 전체 출력과 운영 INSERT 로그는 보존되지 않았습니다. 따라서 정확한 발생 시각·실패 건수는 공개 기록에 넣지 않았습니다. 다음 단계는 CI에서 빈 MySQL을 올리고 schema.sql 적용과 CRUD 스모크 테스트를 자동화하는 것입니다.

14 · LEARNING

배운 점

데이터베이스 오류를 애플리케이션 코드만 보고 판단해서는 안 됐습니다. 쓰기 로직이 전제하는 키 생성·기본값·제약조건이 실제 배포된 스키마와 일치하는지 런타임에서 확인해야 합니다.