Ответ
Миграция базы данных — это управляемое, версионное изменение схемы БД (таблицы, столбцы, индексы, ограничения), которое позволяет эволюционировать структуре данных параллельно с развитием приложения, сохраняя при этом существующие данные.
Зачем это нужно:
- Добавление нового функционала, требующего новых таблиц или полей.
- Рефакторинг существующей схемы (переименование, изменение типа).
- Внесение исправлений (багфиксы) в структуру БД.
- Обеспечение идентичности схемы БД во всех окружениях (разработка, тестирование, продакшн).
Базовый пример на SQL:
-- Миграция '001_add_user_age.sql' (накат)
ALTER TABLE users ADD COLUMN age INTEGER;
-- Соответствующий откат (rollback)
ALTER TABLE users DROP COLUMN age;
Как это работает в контексте C++ проекта: На практике для C++ приложений миграции часто управляются внешними инструментами (Flyway, Liquibase) или скриптами. Процесс выглядит так:
- Версионность: Каждая миграция — это файл с SQL или кодом на C++, имеющий уникальный номер или метку времени (например,
20240515_01_add_email.sql). - Журнал применений: В БД создается служебная таблица (например,
schema_version), которая отслеживает, какие миграции уже применены. - Применение: Инструмент миграций сравнивает журнал с доступными файлами миграций и применяет недостающие в правильном порядке.
- Откат: Для каждой миграции часто пишется обратный SQL-скрипт, позволяющий отменить изменения при необходимости.
Пример организации в проекте:
database/
├── migrations/
│ ├── 001_initial_schema.sql
│ ├── 002_add_user_age.sql
│ └── 003_create_index_on_email.sql
└── deploy_scripts/ (запускает миграции в правильном порядке)
Ключевой принцип: Миграции должны быть идемпотентными — их повторное применение не должно ломать схему. Это часто достигается использованием конструкций вроде CREATE TABLE IF NOT EXISTS или проверкой существования столбца перед ALTER TABLE.