미기록 항목의 실제 실행 조건을 읽기 전용으로 확인해 실행 불필요 상태를 구분한다. 명시적 요청에서 선행 항목부터 확인 이력을 등록하고 등록 버튼을 왼쪽에 배치한다. 부분 적용·게시판별 컬럼·조회 오류와 순차 등록·실패 이력·체크섬·잠금 보호 검증을 추가한다.
7.5 KiB
데이터베이스 마이그레이션
데이터베이스 스키마 변경은 설정·목록·상세 화면이나 공통 라이브러리의 일반 실행 경로에서 수행하지 않는다. 신규 설치의 최종 스키마는 install/gnuboard5.sql에 반영하고, 기존 설치 변경은 migrations 디렉터리의 버전형 SQL 파일로 관리한다.
파일 규칙
- 파일명은
YYYYMMDD_NNN_설명.sql형식을 사용한다. - 파일명은 한 번 배포한 뒤 변경하거나 재사용하지 않는다.
-- @description에 관리자에게 표시할 설명을 작성한다.- 각 SQL 문 바로 앞에
-- @if-table-missing,-- @if-table-exists,-- @if-column-missing,-- @if-index-missing조건을 둘 수 있다. 조건이 여러 개면 모두 만족할 때만 실행한다. - 게시판별 글 테이블은
-- @foreach-write-table-if-column-missing column_name과{{write_table}}을 사용한다. - SQL에는 실제 접두어 대신 실행기가 지원하는 테이블 자리표시자를 사용한다.
- 한 파일은 가능한 한 하나의 목적만 포함한다.
자리표시자는 $g5에 등록된 *_table 키를 {{config_table}} 형식으로 사용한다. 실행기가 실제 테이블명으로 치환하며, 치환되지 않은 자리표시자는 오류로 처리한다.
실행 방법
CLI를 권장한다.
php bin/db-migrate.php status
php bin/db-migrate.php record-existing
php bin/db-migrate.php migrate
php bin/db-migrate.php migrate 20260416_001_member_auto_login
php bin/check-migration-schema.php
php bin/check-migration-runner.php
php bin/check-migration-existing.php
php bin/check-shop-install.php
php bin/check-runtime-ddl.php
웹에서는 최고관리자가 환경설정 → DB업그레이드에서 전체 또는 특정 마이그레이션을 명시적으로 실행할 수 있다. 성공한 마이그레이션의 개별 실행 버튼은 비활성화되며, 전체 실행에서도 성공 이력과 체크섬이 일치하는 항목은 건너뛴다. 화면 조회만으로는 DDL이 실행되지 않는다.
기존 설치본처럼 이력이 비어 있으면 상태 조회 시 실제 실행 조건을 읽기 전용으로 검사한다. 일부 이력이 있는 경우에도 미기록 항목은 검사한다. 현재 조건에서 모든 SQL을 건너뛰는 항목은 실행 불필요 (미기록)로 표시하며 개별 실행 버튼을 비활성화한다. 이는 과거 실행 성공이나 컬럼 정의 전체의 일치를 보증하는 표시가 아니다. 게시판별 컬럼도 검사하며, 조건 없는 DDL·데이터 보정·검사 오류는 대기로 남긴다. 조회 요청 안에서는 메타데이터를 공유해 중복 조회를 줄이고, 다음 요청에서는 다시 검사하므로 외부 변경이나 선행 작업 후 상태가 반영된다.
기존 상태 확인 이력 등록 버튼 또는 CLI record-existing은 실행 잠금 아래 다시 검사하고, 처음부터 연속해서 실행 불필요한 미기록 항목만 성공 이력으로 등록한다. 등록 시각은 확인한 시각이며 실제 과거 적용 시각이 아니다. 이 동작은 필요하면 이력 테이블을 생성하지만, 마이그레이션 SQL 자체는 실행하지 않는다. 변경이 필요한 항목이나 실패 이력을 만나면 중단하며, 성공 이력의 체크섬 불일치는 오류로 처리한다. 화면 진입만으로 등록하지 않으며 웹 등록은 최고관리자 권한과 POST 토큰 검증을 거친다. 전체 마이그레이션 실행도 기존처럼 실행 조건을 다시 확인하고 건너뛴 항목의 이력을 함께 기록한다.
전체 실행은 파일명 오름차순, 즉 오래된 마이그레이션부터 처리하며 하나가 실패하면 이후 실행을 중단한다. 개별 실행도 대상보다 앞선 모든 마이그레이션의 성공 이력과 체크섬이 유효해야 한다. 선행 항목이 누락·실패·변경된 경우 대상만 건너뛰기 성공으로 기록하지 않고 오류로 차단한다.
실행기는 g5_migrations 테이블에 마이그레이션 ID, 체크섬, 상태, 오류, 실행시간과 적용시각을 기록한다. 프로세스 간 잠금을 사용해 동시 실행을 막고, 실패하면 이후 마이그레이션을 중단한다. 적용이 끝난 파일의 체크섬이 바뀌면 오류로 처리한다.
현재 마이그레이션은 공통 실행 취소를 제공하지 않는다. 컬럼·테이블 삭제에 따른 데이터 손실과 후속 마이그레이션 의존성을 자동으로 안전하게 해결할 수 없기 때문이다. g5_migrations의 성공 이력만 삭제하는 것도 실제 스키마를 되돌리지 않으므로 취소로 취급하지 않는다. 롤백이 필요하면 데이터베이스 백업을 복원하거나, 해당 변경에 맞춘 별도 복구 절차를 검토한다.
check-migration-schema.php는 마이그레이션의 테이블·컬럼·인덱스가 신규 설치 SQL에 포함되는지와 최종 컬럼 정의가 일치하는지 검사한다. check-migration-runner.php는 격리된 임시 테이블로 부분 적용 스키마, 쇼핑몰 미설치 건너뛰기, 기존 데이터 보정을 검사한다. 마이그레이션을 추가하거나 설치 SQL을 변경한 뒤 두 검사를 반드시 실행한다.
check-migration-existing.php는 실제 DB 대신 SQL 응답을 제공해 조회 시 쓰기 금지, 순차 이력 등록, 재검사, 실패 이력·체크섬·잠금 보호를 검사한다. 기존 상태 검사나 이력 등록 로직을 변경한 뒤 실행한다.
쇼핑몰을 설치하지 않은 사이트에서는 DB 업그레이드 화면의 쇼핑몰 설치 버튼으로 최신 쇼핑몰 스키마를 추가할 수 있다. 같은 접두어의 쇼핑몰 테이블이 하나라도 있으면 기존 데이터 훼손을 막기 위해 설치를 중단하며, 기존 data/dbconfig.php의 DB 접속 정보와 토큰 키는 유지하고 쇼핑몰 설정만 추가한다. php bin/check-shop-install.php로 격리된 접두어에서 후설치, 설정 보존과 중복 실행 차단을 검사할 수 있다.
check-runtime-ddl.php는 관리자·게시판·라이브러리·쇼핑몰 등 일반 실행 경로에 DDL 문이 다시 추가되지 않았는지 검사한다. 테이블이나 컬럼 변경은 이 검사를 우회하지 말고 버전형 마이그레이션으로 작성한다.
게시판 삭제 시 게시판별 테이블을 함께 삭제하는 것처럼 사용자가 명시적으로 요청한 데이터 생명주기 작업은 마이그레이션과 구분해 제한된 허용 목록으로 관리한다. 일반 레코드 생성 과정에서 AUTO_INCREMENT를 초기화하는 DDL은 허용하지 않는다.
권한과 배포
운영 환경에서는 웹 런타임 DB 계정에서 DDL 권한을 제거하고, 배포 단계에서 별도의 권한을 가진 계정으로 CLI 마이그레이션을 실행하는 구성을 권장한다. 웹 실행 기능을 사용하는 환경은 실행 시에만 필요한 DDL 권한이 있어야 한다.
배포 전에는 백업과 테이블 크기, 예상 잠금 시간을 확인한다. MySQL 계열 DB의 DDL은 트랜잭션으로 완전히 되돌릴 수 없으므로 실패한 마이그레이션의 오류를 확인하고 수동 복구 후 재실행한다.
기존 업그레이드 코드
과거 설치본을 화면 접근 시점에 보정하던 누적 DDL은 일반 실행 파일에서 제거했다. orderupgrade.php와 adm/dbupgrade.php에 누적됐던 배포 후 변경은 실제 도입 시점별 마이그레이션으로 이전했다. 조사 근거와 대응 목록은 database-migration-history.md에 기록한다.