Привет, хабр! Меня зовут Кирилл Курдюков, я разработчик YDB.
В этой статье мы рассмотрим, как начать использовать диалект YDB (YQL) в Liquibase для управления миграциями схемы данных.
Введение
В современном мире разработки ПО управление версиями схемы данных стало критически важной задачей для обеспечения согласованности состояния СУБД с приложением клиента и отката изменений. Инструменты миграции базы данных, такие как Liquibase, предоставляют средства для версионирования, отслеживания и применения изменений схемы данных.
Однако, появление новых СУБД ставит задачу интеграции с этими системами для поддержки их диалектов SQL.
Как раз о результатах интеграции диалекта YDB c Liquibase мы и поговорим в этой статье.
Возможности диалекта YDB и переносимость стандарта описания changeset'ов Liquibase
Основной функциональностью Liquibase является абстрактное описание схемы базы данных в форматах .xml
, .json
, .yaml
. Что обеспечивает переносимость при смене одной СУБД на другую.
Для YDB поддержаны следующее основные конструкции:
createTable
создание таблицы. Описание типов данных из SQL стандарта сопоставляется с примитивными типами YDB. К примеру, типbigint
будет конвертирован вInt64
. Также можно явно указывать оригинальное название, например, такие типы какUint32
,Json
,JsonDocument
,Bytes
,Interval
. Но в таком случае теряется переносимость схемы на другие СУБД.dropIndex
,createIndex
,addColumn
,dropTable
. Соответственно, удаление, создание индекса и добавление колонки, удаление таблицы.loadData
,loadUpdateData
загрузка данных из CSV файлов.insert
единичная вставка в таблицу.
На момент написания статьи есть ограничения с классическими конструкциями SQL. Например, в версии YDB 23.3 вторичный индекс не может быть уникальным.
Важно отметить, что кастомные инструкции YQL можно применять через нативные SQL запросы. Но YDB не стоит на месте! В дальнейшем все больше и больше классических SQL конструкций будет поддержано.
Чтобы понять, какие SQL-конструкции может выполнять YDB, ознакомьтесь с документацией по языку запросов YQL.
Как воспользоваться?
Есть два способа:
программно из Java / Kotlin приложения
liquibase CLI
Как воспользоваться из Java / Kotlin подробно описано в README проекта, там же есть ссылка на пример Spring Boot приложения.
Пример использования диалекта
Установка
Для начала нужно установить саму утилиту liquibase любым из рекомендуемых способов.
Затем нужно подложить актуальные .jar архивы YDB JDBC драйвера и Liquibase диалекта YDB.
# $(which liquibase)
cd ./internal/lib/
# you may need to sudo
# set an actual versions .jar files
curl -L -o ydb-jdbc-driver.jar https://repo.maven.apache.org/maven2/tech/ydb/jdbc/ydb-jdbc-driver-shaded/2.0.7/ydb-jdbc-driver-shaded-2.0.7.jar
curl -L -o liquibase-ydb-dialect.jar https://repo.maven.apache.org/maven2/tech/ydb/dialects/liquibase-ydb-dialect/1.0.0/liquibase-ydb-dialect-1.0.0.jar
Более подробное описание в разделе Manual library management. Теперь liquibase
утилитой можно пользоваться стандартными способами.
Настройка
Напишем простенький liquibase.properties
:
changelog-file=changelogs.xml
url=jdbc:ydb:grpc://localhost:2136/local
changelog-file - относительный путь к файлу миграций
url - локальный докер контейнер YDB
Создание первой таблицы
Создадим первую таблицу episodes и загрузим в нее из CSV
файла данные.
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">
<changeSet id="episodes" author="kurdyukov-kir">
<comment>Table episodes.</comment>
<createTable tableName="episodes">
<column name="series_id" type="bigint">
<constraints primaryKey="true"/>
</column>
<column name="season_id" type="bigint">
<constraints primaryKey="true"/>
</column>
<column name="episode_id" type="bigint">
<constraints primaryKey="true"/>
</column>
<column name="title" type="text"/>
<column name="air_date" type="timestamp"/>
</createTable>
<createIndex tableName="episodes" indexName="episodes_index" unique="false">
<column name="title"/>
</createIndex>
<rollback>
<dropTable tableName="episodes"/>
</rollback>
</changeSet>
</databaseChangeLog>
Содержимое файла changelogs.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.8.xsd">
<include file="migration/episodes.xml" relativeToChangelogFile="true"/>
<changeSet id="episodes-from-csv" author="kurdyukov-kir" context="all">
<loadData tableName="episodes" file="./migration/csv/episodes.csv" relativeToChangelogFile="true"/>
</changeSet>
</databaseChangeLog>
После исполнения liquibase update
Liquibase напечатает лог исполненных миграций.
Running Changeset: migration/episodes.xml::episodes::kurdyukov-kir
Running Changeset: changelogs.xml::episodes-from-csv::kurdyukov-kir
UPDATE SUMMARY
Run: 2
Previously run: 0
Filtered out: 0
-------------------------------
Total change sets: 2
Результатом будет таблица episodes c добавленными записями:
Далее в своей базе данных можно увидеть созданные Liquibase две системные таблицы: DATABASECHANGELOG
, DATABASECHANGELOGLOCK
.
Эволюционируем таблицу episodes
Далее допустим, что наша схема базы данных нуждается в дополнительных изменениях:
Добавим новую колонку
is_deleted
типа Bool.Удалим индекс.
Допишем в changelogs.xml следующий changeset:
<changeSet id="alter-episodes" author="kurdyukov-kir">
<comment>Alter table episodes.</comment>
<dropIndex tableName="episodes" indexName="episodes_index"/>
<addColumn tableName="episodes">
<column name="is_deleted" type="bool"/>
</addColumn>
</changeSet>
Лог команды liquibase update
:
Running Changeset: changelogs.xml::alter-episodes::kurdyukov-kir
UPDATE SUMMARY
Run: 1
Previously run: 2
Filtered out: 0
-------------------------------
Total change sets: 3
Результатом будет добавление новой колонки is_deleted и удаление индекса:
Миграция нативных YQL конструкций
Создание YDB топика и выключение автоматического партицирования:
--liquibase formatted sql
--changeset kurdyukov-kir:create-a-topic
CREATE TOPIC `my_topic` (
CONSUMER my_consumer
) WITH (
retention_period = Interval('P1D')
);
ALTER TABLE episodes SET (AUTO_PARTITIONING_BY_SIZE = DISABLED);
Changeset соответствующий:
<include file="/migration/sql/yql.sql" relativeToChangelogFile="true"/>
Лог выполнения миграций:
Running Changeset: migration/sql/yql.sql::create-topic::kurdyukov-kir
Running Changeset: migration/sql/yql.sql::auto-partitioning-disabled::kurdyukov-kir
UPDATE SUMMARY
Run: 2
Previously run: 3
Filtered out: 0
-------------------------------
Total change sets: 5
Результатом будет создание топика my_topic
и выключение автоматического партицирования:
Поддержка и контакты
Если вы столкнулись с какой-то проблемой или у вас есть идея по улучшению диалекта, то можно открыть issue в репозитории ydb-java-dialects с тэгом liquibase
.
Либо приходите обсудить её в публичный Telegram чат YDB.