В процессе работы над приложением, команда разработчиков часто сталкивается с необходимостью версионирования и трансляции изменений в структуре базы данных между различными машинами. Для этих целей сообществом были разработаны различные системы, отличающиеся функциональными возможностями, ценой (включая бесплатные решения) и технологиями организации процесса.
В качестве примера можно привести:
В этой статье я бы хотел подробнее остановиться на Nasgrate
Основные преимущества Nasgrate
в качестве хранилища SQL-запросов используются обычные текстовые файлы без привязки к какому либо языку программирования. Это упрощает процесс взаимодействия между командами, работающими с разными технологиями (например Node и Python) не приходится разбираться в особенностях язковых конструкций
возможность автоматического создания миграции на основе анализа изменений в двух базах данных (пока поддерживается только MySQL, но в планах другие базы данных) или между двумя состояниями миграций одной базы данных
наличие визуального интерфейса (а не только консольного клиента) позволяющего организовать просмотр изменений в наглядном виде
Nasgrate написан на php. Для удобства можно использовать Docker контейнер или создать phar файл
Для запуска системы необходимо указать параметры подключения к базе данных, а также ряд вспомогательных параметров. Параметры можно указать непосредственно при запуске контейнера, но на мой взгляд лучше это сделать в .env файле
Пример передачи параметров при запуске
$ docker run -it --rm -v $(pwd)/data:/usr/src/nasgrate/data \
-e DATABASE_DRIVER=mysql \
-e DATABASE_HOST=host.docker.internal \
-e DATABASE_NAME=[database name] \
-e DATABASE_USER=[database user] \
-e DATABASE_PASSWORD=[database password] \
-e DATABASE_PORT=[database port] \
-e VERSION_TABLE_NAME=__migrationVersions \
-e DIR_MIGRATION=data/migrations \
-e DIR_DBSTATE=data/dbstate \
-e DEFAULT_DESCRIPTION_MESSAGE='Created by CURRENT_USER, CURRENT_DATE' \
-e CURRENT_USER=[your name] \
dlevsha/nasgrate generate MyFirstMigration
Пример передачи .env файла
$ docker run -it --rm -v $(pwd)/data:/usr/src/nasgrate/data --env-file=.env dlevsha/nasgrate generate MyFirstMigration
Папку с миграциями лучше хранить в репозитории с основным кодом приложения.
В настоящий момент поддерживаются
mysql - MySQL database
sqlsrv - MS SQL Server and SQL Azure databases
mssql - FreeTDS
pgsql - PostgreSQL
oci - Oracle
Все необходимое для работы с этими базами данных уже настроено внутри docker-контейнера (особенно это актуально для Oracle)
При работе с docker контейнером есть особенность по передачи хоста для подключения DATABASE_HOST.
Если Ваша база данных находится, например, на локальной машине, то в качестве хоста для подключения необходимо передавать host.docker.internal. Если Вы используете Nasgrate например внутри сети, созданной docker-compose, то Вам необходимо получить IP для подключения.
docker exec [database container name] cat /etc/hosts | tail -n 1 | cut -d$'\t' -f 1
Более подробно о подключении можно почитать в документации.
Для вызова визуальной части необходимо выполнить
docker run -it --rm -v $(pwd)/data:/usr/src/nasgrate/data --env-file=docker/nasgrate/.env -p 9001:9000 --entrypoint php dlevsha/nasgrate -S 0.0.0.0:9000
и вызвать в броузере
http://localhost:9001/app/
После этого Вы увидите что то вроде
Где слева представлен список миграций, а слева их содержимое. Кликая слева на конкретную миграцию, можно справа увидеть ее содержимое
В папке /bin содержится файл migrations.sh, который после настроек можно использовать для краткости вызова (я обычно добавляю на него alias в .bashrc)
alias nasgrate='/var/www/project/docker/nasgrate/migrate.sh '
Кратко пройдемся по функционалу
Nasgrate is a console utility that let you organise database schema migration process at a consistent and easy way.
It supports mysql, mssql, postgresql, oracle (you can find informaton here http://php.net/manual/en/pdo.drivers.php)
Usage:
nasgrate [command] [options]
Command:
status - displays migration status
generate - creates new migration (migration file)
diff - save current database state and create migration with database schema diff
up:show - displays (but not executes) SQL-query, executed by migration update
down:show - displays (but not executes) SQL-query, executed by migration revert
up - executes migration update
down - executes migration revert
help - shows this help page
Для создания новой миграции необходимо вызвать (здесь и в дальнейшем, я использую alias из .bashrc, описанный выше)
$ nasgrate generate CreateTestMigration
В папке migrations будет создан файл такой структуры
-- Skip: no
-- Name: Test
-- Date: 01.12.2020 20:28:08
-- Description: Created by dlevsha, 2020-12-01 20:28:08
-- UP --
-- DOWN --
Skip отвечает за то, нужно ли пропустить данную миграцию (например вы не хотите чтобы она была выполнена на dev машине, но хотите выполнить ее на prod)
Name - "заголовок миграции" миграции
Формат Description можно задать через параметр DEFAULT_DESCRIPTION_MESSAGE. Можно использовать place holder CURRENT_USER и CURRENT_DATE, которые будут заменены на дату и имя текущего пользователя, создающего миграцию
В секцию UP добавляются скрипты с "прямой" миграцией, в секцию DOWN скрипты "обратной" миграции.
Например так мог бы выглядеть файл миграций
-- Skip: no
-- Name: Test
-- Date: 01.12.2020 20:28:08
-- Description: The first migration. Created by dlevsha, 2023-09-01 20:28:08
-- UP --
CREATE TABLE test (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE test2 (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DOWN --
DROP TABLE test;
DROP TABLE test2;
По собственным наблюдениям и по наблюдениям коллег, "обратные" миграции используются значительно реже, чем "прямые", поскольку они могут привести к потере данных (DROP TABLE все таки). Используйте "обратные" миграции с осторожностью.
Для просмотра миграций используется команда list
$ nasgrate list
Выведет
Migration list:
- [26.08.2020 19:39:39] 20200826193939_CreateFirstMigration - new
- [26.08.2020 19:30:33] 20200826193033_New_Table_Test - executed
Команды up и up:show отвечают соотвественно за выполнение и предварительный просмотр "прямой миграции"
Команды down и down:show отвечают соотвественно за выполнение и предварительный просмотр "обратной миграции"
Более подробно об особенностях работы этих режимов можно почитать в документации.
Отдельно хотел бы остановиться на уникальной функции генерации миграций между двумя базами данных или между двумя состояниями одной базы данных. Создан этот режим на основе системы визуального сравнения схем баз данных Compalex (статья на Хабр)
Для включения данной функции нужно указать параметр VERSION_CONTROL_STRATEGY, который принимает два состояния: file и database
В состоянии file система сохраняет в сериализованном виде текущее состояние базы данных на момент создания новой миграции. После этого при выполнении команды
$ nasgrate diff AddNewTable
будет проведено сравнение между актуальным состоянием базы данных и данными, сохраненными с создания последней миграции, и автоматически будет создан файл миграций с SQL-запросами, отражающими эти изменения.
В состоянии database, нужно будет дополнительно заполнить параметры для подключения ко второй базе данных. В этом случае система будет сравнивать две базы данных и генерировать файл миграции с SQL-запросами, описывающими разницу между двумя базами данных.
В заключении хотелось бы сказать о важности организации изменений в базах данных и о выборе подходящего инструмента для этого процесса.
dph
Лучше не использовать инструменты миграции данных только вокруг SQL и не использовать инструменты, порождающие код миграции. Тогда проблем при сопровождении будет гораздо меньше.