소개
작은 매장이 픽업 장소를 추가하고 있습니다. 기존 주문 클라이언트는 주문 ID, 고객, 정수 센트, 메모를 제공하며 새 주문 클라이언트는 픽업 코드도 제공합니다. 기존 주문과 상품 관계는 계속 사용할 수 있어야 합니다. 기본값은 열 생략의 호환성을 유지하지만 과거 고객이 실제로 어디서 주문을 받기로 했는지는 알려 주지 않습니다.
expand.sql과 확장된 실제 주문 테이블을 완성하고 준비된 두 클라이언트를 사용한 뒤, 데이터 트랜잭션과 MySQL DDL 사이의 실제 경계를 관찰합니다. 기본적인 터미널 탐색, MySQL SELECT/WHERE, INSERT/UPDATE, 열, 기본 키, 기본값 지식이 필요합니다. Python이나 애플리케이션 개발은 필요하지 않습니다. 이 독립 단원에는 자체 전용 Oracle MySQL과 Terminal이 제공됩니다. 일반 데이터베이스 서비스는 관련이 없습니다.
/home/labex/project/pickup-desk에서만 작업하세요. 명시된 픽업 열을 orders에 추가하고, 시연에서는 격리된 ddl_demo만 갱신/확장할 수 있습니다. 원래 주문 ID, 고객, 금액, 메모, 상품, 픽업 장소, 승인 테이블과 제공된 도구를 모두 보존하세요. 아래에 이름이 지정된 연습 주문 세 개만 추가할 수 있습니다. 이는 통제된 유지보수 시간의 작업이며 온라인, 잠금 없음, 무중단 마이그레이션이 아닙니다. 저자의 예상 시간에는 읽기와 일반적인 실수가 포함되며 초보자를 대상으로 시간을 측정하지 않았습니다.
두 클라이언트의 동작을 유지하며 스키마 확장하기
이 단계에서는 정상적인 기존 방식 주문을 만들고 호환되는 픽업 열을 추가하며, 두 클라이언트 버전이 만든 실제 주문을 읽습니다.
셸 프롬프트의 Terminal에서 시작하세요. cd는 현재 디렉터리를 바꾸며 절대 경로는 어느 시작 디렉터리에서도 동작합니다. ./shop은 그 디렉터리의 준비된 명령을 실행합니다. 이들은 셸 명령이며 MySQL 프롬프트의 입력이 아닙니다:
cd /home/labex/project/pickup-desk
./shop status
./shop points
원래 주문 헤더는 101 / Sam / 2100, 102 / Sam / 3400, 103 / Lee / 0이며 각각 메모와 상품이 있습니다. 두 Sam 주문은 서로 다른 식별 정보를 가집니다. 금액은 정수 센트이고 0도 유효합니다. status와 show는 실제 저장 값을 읽으며 레코드를 마이그레이션하거나 픽업 선택을 대체하지 않습니다.
준비된 기존 클라이언트는 old order_id customer total_cents sku quantity를 받습니다. 명시적인 기존 열 이름으로 헤더를 삽입하고 같은 MySQL 트랜잭션에서 상품을 삽입합니다. 성공한 호출은 커밋합니다. MySQL 자체 SQL 오류는 배치를 멈추고 연결을 닫으며 보류 중인 데이터 변경을 롤백합니다. 허용된 일반 주문을 만들고 읽으세요:
./shop old 201 Mina 1600 MUG 1
./shop show 201
헤더에는 ID 201, Mina, 1600, Created by legacy client가 있으며 상세에는 MUG, 수량 1이 있습니다. 반환된 pickup_column: false는 필드가 아직 배포되지 않았음을 뜻합니다. 새 클라이언트는 같은 인수 뒤에 픽업 코드를 받습니다. 다음 명령은 알 수 없는 열 pickup_code에 대한 MySQL 오류 1054와 0이 아닌 종료 상태로 실패하는 것이 의도된 결과입니다. 헤더나 상세를 남기면 안 됩니다:
./shop new 203 Pia 1900 CARD 2 garden
./shop show 203
읽기는 빈 헤더/상품을 보여 줍니다. 열이 없는 것은 스키마 오류이며 알 수 없는 픽업 코드나 주문 처리에 성공한 빈 결과가 아닙니다.
명시적 기본값이 counter인 NULL을 허용하는 새 열을 추가하세요. ALTER TABLE은 정의를 변경하고 ADD COLUMN은 필드를 추가합니다. VARCHAR(16)은 짧은 픽업 코드를 저장합니다. NULL은 확장 단계에서 명시적인 미확정 값을 잠시 허용합니다. DEFAULT 'counter'는 기존 클라이언트가 열을 생략할 때 호환 값을 제공합니다. 확장 후 기존 행에도 나타나므로 과거 선택의 증거가 아닙니다. 다음 독립 실습에서 최종 규칙을 강화하기 전에 승인된 과거 기록을 처리합니다.
완전한 SQL 파일을 저장하세요. cat > expand.sql은 이 파일 하나를 덮어씁니다. 따옴표로 지정한 here-document 표시 'SQL'은 셸이 마지막 단독 SQL까지 줄들을 그대로 복사하게 합니다. 각 SQL 문은 세미콜론으로 끝납니다:
cat > expand.sql <<'SQL'
ALTER TABLE orders ADD COLUMN pickup_code VARCHAR(16) NULL DEFAULT 'counter';
SQL
apply는 과정의 마이그레이션 역할을 사용해 MySQL 기본 배치 연결 하나에서 저장 파일을 변경 없이 실행합니다. 누락된 SQL을 추론하거나 과거 값을 채우거나 고치지 않습니다:
./shop apply expand.sql
./db -e "SHOW COLUMNS FROM orders;"
./db는 이 과정의 전용 데이터베이스에 연결합니다. -e는 뒤의 따옴표 안 SQL을 실행하고 종료합니다. 큰따옴표는 공백과 세미콜론을 셸 인수 하나로 유지합니다. 픽업 열의 자료형, NULL 허용 여부, 기본값을 읽으세요. varchar(16), YES, counter입니다. 다른 원래 필드도 남아 있습니다.
기존 클라이언트를 다시 사용하고 앞서 거부된 새 주문을 재시도하세요:
./shop old 202 Omar 1800 BAG 1
./shop new 203 Pia 1900 CARD 2 garden
./shop show 201
./shop show 202
./shop show 203
./shop status
주문 201과 202에는 실제 저장된 기본값 counter가, 203에는 garden이 있습니다. 모든 헤더와 실제 상품 행이 남습니다. 원래 주문 세 개는 이제 확장 기본값 counter를 표시합니다. 모든 과거 주문을 거기서 수령했다고 주장하지 마세요. 준비된 승인 매핑은 그대로 유지됩니다.
일반적인 ./shopp 오타는 ls를 실행하고 올바른 이름 ./shop을 사용하세요. SQL이 구문 오류를 보고하면 cat expand.sql을 확인하고 저장한 전체 문장을 수정한 뒤 열이 아직 없을 때만 적용하세요. 확장 반복의 오류 1060은 열이 이미 있다는 뜻입니다. 열을 삭제하거나 데이터베이스를 초기화하지 말고 SHOW COLUMNS를 확인하세요. 성공한 클라이언트 주문을 반복하면 중복 ID 오류가 납니다. 다른 ID를 만들지 말고 show로 기존 주문을 보세요. 명시된 허용 주문과 원본 데이터를 유지하세요.
롤백이 취소하지 못하는 것 관찰하기
이 단계에서는 주문 시스템을 그대로 유지하며 별도의 시연 테이블에서 MySQL 자체 ALTER 경계를 관찰합니다.
계속 Terminal의 /home/labex/project/pickup-desk에서 작업하세요. ddl_demo는 모든 주문과 분리된, 명시적으로 폐기 가능한 한 행짜리 교육용 테이블입니다. 초기 메모는 original입니다:
./db -e "SELECT * FROM ddl_demo;"
트랜잭션은 COMMIT이나 ROLLBACK까지 데이터 변경을 묶습니다. START TRANSACTION은 트랜잭션을 시작하고 UPDATE는 선택 행을 바꾸며 ROLLBACK은 일반적으로 커밋되지 않은 데이터 변경을 버립니다. ALTER TABLE을 포함한 MySQL DDL(데이터 정의어)에는 암묵적 커밋 경계가 있습니다. ALTER는 정의 변경 전에 앞선 작업을 커밋하며 나중의 사용자 ROLLBACK으로 취소되지 않습니다. 원자적 DDL 복구는 사용자 DDL을 롤백 가능하게 만드는 것과 다릅니다.
다음 파일은 이 시연 메모만 의도적으로 바꾼 뒤 NULL을 허용하는 정수 열 extra를 추가하고 ROLLBACK을 요청합니다. 실행 전에 메모와 새 열이 남을지 예상하세요:
cat > ddl-demo.sql <<'SQL'
START TRANSACTION;
UPDATE ddl_demo SET note='committed before ALTER' WHERE id=1;
ALTER TABLE ddl_demo ADD COLUMN extra INT NULL;
ROLLBACK;
SQL
./shop apply ddl-demo.sql
./db -e "SELECT * FROM ddl_demo;"
./db -e "SHOW COLUMNS FROM ddl_demo;"
행의 메모는 여전히 committed before ALTER이며 extra는 NULL입니다. SHOW COLUMNS에도 extra가 나옵니다. 앞선 데이터 UPDATE는 ALTER에 의해 커밋되었고 새 정의도 남습니다. ROLLBACK이 성공적으로 반환되어도 취소하지 못했습니다. 이는 만들어 낸 출력 파일이 아니라 실제 서버 동작입니다.
실제 주문을 다시 읽으세요:
./shop show 101
./shop show 201
./shop show 203
원래 헤더 값, 메모, 상품, 저장된 픽업 코드가 남습니다. 주문 메모에 이 시연을 수행하지 마세요. 실제 마이그레이션은 트랜잭션으로 수행하는 과거 데이터 채우기와 이후 규칙 강화 DDL을 분리하고 그에 맞게 유지보수/복구 경계를 계획합니다. 모든 ALTER를 BEGIN 안에 둔다고 자동 롤백이 제공되지는 않습니다.
시연 파일은 명시된 초기 정의에서 한 번 실행하는 스크립트입니다. 실수로 두 번 실행하면 extra가 이미 있습니다. 실제 시연 정의와 행을 확인하세요. 두 번째 실행을 새 실행처럼 보이게 하려고 삭제하지 마세요. 첫 성공 적용 전에는 잘못 입력한 파일을 전체 블록으로 복원하세요. 이 단원은 호환되는 확장과 사실에 맞는 DDL 관찰로 끝나며, 지속적인 운영 트래픽에서 배포했다고 주장하지 않습니다.
요약
호환되는 주문 테이블 확장을 완성하고 실제 기존/새 클라이언트 쓰기를 관찰하며 원래 주문 상세를 보존했습니다. 격리된 MySQL 자체 실험으로 성공한 ROLLBACK이 ALTER나 그 앞서 커밋된 데이터 변경을 취소하지 못하는 이유를 확인했습니다. 과거 픽업 선택에는 다음에 배울 승인 매핑이 여전히 필요합니다.



