Go: GORM
Теория: Миграции схемы базы
После подключения к базе и определения моделей возникает следующая задача: привести схему базы данных в соответствие с кодом. Модели описывают сущности и поля, но сама база пока ничего об этом не знает. Миграции схемы как раз и отвечают за то, чтобы таблицы создавались, обновлялись и не расходились с кодом. В GORM эту роль частично берёт на себя механизм AutoMigrate(): он читает структуры и автоматически применяет изменения к схеме.
AutoMigrate и создание таблиц
AutoMigrate() работает как мост между моделями и базой данных. Функция просматривает структуру, сравнивает её с текущей схемой и, при необходимости, создаёт недостающие таблицы и столбцы. Если таблицы ещё нет, GORM строит её с нуля. Если она уже существует, AutoMigrate() аккуратно добавляет новые поля, но не удаляет старые и не меняет типы существующих колонок. Такой режим безопасен для ранних этапов разработки, когда нужно быстро поднять рабочую базу.
Простейший пример миграции показывает эту механику на модели пользователя:
При запуске этого кода GORM проверяет наличие таблицы users. Если таблицы нет, она создаётся с колонками id, name, email и age. Если таблица существует, но, например, поле age было добавлено позже, AutoMigrate() создаст недостающий столбец. При этом существующие данные остаются на месте, а базовая структура обновляется под текущую модель.
Обновление схемы через код
Когда модель меняется, то же должно произойти и с базой. Добавление поля в структуру, изменение ограничений через теги или добавление служебных колонок приводят к необходимости обновить схему. В простых случаях это делается тем же вызовом AutoMigrate(). Код остаётся тем же, а миграция повторно сравнивает модель с таблицей и вносит изменения.
Например, если к модели User добавить временные поля и мягкое удаление, схема расширится:
Повторный вызов AutoMigrate():
добавит в таблицу users новые колонки created_at, updated_at и deleted_at, если их не было. Индекс по deleted_at появится автоматически. Существующие строки получат NULL в новых полях, а всё последующее создание и обновление записей начнёт заполнять эти значения.
Через код удобно обновлять и связи между таблицами. Если к системе пользователей добавить заказы, модели и миграция могут выглядеть так:
В этом сценарии GORM создаёт таблицу orders, добавляет колонку user_id и индекс по ней. Дополнительные ограничения, такие как каскадное обновление и поведение при удалении, можно описать через теги в модели Order(). AutoMigrate() учитывает эти настройки и отражает их в схеме, насколько это поддерживается выбранной СУБД.
Как миграции работают под капотом
Внутри AutoMigrate() действует по простой, но аккуратной схеме. Сначала GORM считывает описание структуры: имена полей, типы, теги, связи. Затем библиотека запрашивает у базы текущую информацию о таблицах и колонках. На этой основе формируется список различий: какие таблицы отсутствуют, какие поля нужно добавить, какие индексы стоит создать. После этого GORM генерирует и выполняет DDL-запросы: CREATE TABLE, ALTER TABLE ADD COLUMN, CREATE INDEX и другие.
Важно, что AutoMigrate() ориентирован на безопасные изменения. Он не удаляет столбцы, даже если поле исчезло из структуры. Он не меняет типы колонок, если они уже существуют. Такое поведение защищает от потери данных, но означает, что сложные изменения схемы (переименование поля, сжатие типов, удаление колонок) требуют явных миграций на уровне SQL или отдельных инструментов вроде goose. GORM в этом смысле ведёт себя как мягкий помощник: добавляет недостающее, но не ломает существующее.
Под капотом GORM также учитывает особенности разных СУБД. Типы данных, синтаксис создания индексов, поддержка ограничений и внешних ключей зависят от конкретного драйвера. AutoMigrate() переводит абстрактное описание модели в конкретные выражения PostgreSQL, MySQL или другой базы. Благодаря этому один и тот же код миграции может работать с разными системами, если модели заданы достаточно универсально.
В простых проектах AutoMigrate() способен полностью закрыть потребности в эволюции схемы. На этапе активной разработки он позволяет быстро изменять модели и получить актуальную структуру без написания DDL-скриптов. В более зрелых системах его обычно используют осторожно: для небольших дополнений и лайтовых изменений, а крупные рефакторинги схемы оформляют в виде явных миграций с контролем версий.
Подведем итоги
Миграции схемы в GORM строятся вокруг механизма AutoMigrate(). Структуры Go становятся источником правды о данных, а ORM переводит это описание в реальные таблицы и поля. Создание новых сущностей, добавление служебных колонок, настройка связей и индексов выполняются напрямую из кода. Такой подход снижает объём ручного SQL и делает схему ближе к модели предметной области. Важно помнить о границах AutoMigrate(): он умеет добавлять и расширять, но не отвечает за разрушительные изменения. Для сложных сценариев всегда остаётся возможность подключить отдельный инструмент миграций и сочетать оба подхода.



