Pull to refresh

Comments 40

Для тех, кого не возбуждает dsl в yaml, liquibase поддерживает обычный SQL. И да, уж лучше я руками его напишу.
Есть такая возможность! А что с переносимостью на разные БД при этом?
А она и не нужна чаще всего. Это очень редкая операция. Часто видел, слышал, принимал участие в переезде на NoSQL, а вот про переезд на другую реляционную базу — это событие века. И потом, а почему мы выбрали БД, но не используем её фишки? Может они больше профита нам дадут здесь и сейчас, чем мифический переезд на другую базу хз когда в будущем? Кроме того, читать патчи на знакомом и привычном всем SQL намного приятнее, чем на очередном dsl. Конечно же, это ИМХО, в неопределившихся стартапах переносимость мб и нужна.
У меня несколько раз была ситуация, когда локально и для тестирования H2 или MySQL, а в продакшн Postgres, Oracle или что-то еще.
Согласен, это можно записать в use-case кроссплатформенности. Однако, по факту, получается, что в тестах вы тестируете интеграцию с небоевой базой и это может как-нибудь аукнуться. Наверное, скорее всего, с этим большинство проектов не столкнуться, но вероятность есть.

Я с некоторых пор стал предпочитать Testcontainers

неверный подход. Локально, даже для тестирования, надо использовать ту же БД, что и на сервере. Есть же docker сборки или embedded реализации для того же PostgreSQL или OracleDB. В противном случае можно словить коллизии, проявляемые только в конкретной БД конкретной версии и ловить будете эту особенность очень долго

Не делайте так: в проде одна БД, а тесты на другой. Используйте docker-compose для тестирования на нормальной БД.
С docker-compose это и в самом деле становится проще!

На одном проекте была поддержка одновременно Oracle и Postgres. Прилоежние потом устаналивалось клиентам on-prem.

Соответсвенно тестировалось и на том и на том.

Сам ликвибес был на xml. Иногда вставки СКЛ с добавлением ксловия на то под какой базой запущено.

ох уже эти "швейцарские ножи"… крайне редко "переносимость" делается на раз-два — чаще всего всё равно придётся подкручивать, подтягивать или и вовсе переписывать чтобы заработало на другом окружении (БД, ОС, etc). А если пишете "швейцарский нож", то платите за это например просадкой в производительности

Ну так-то, если гонять тесты на всех СУБД, с которыми должно работать приложение — и будет переносимость. Есть гонять тесты только на H2, то и работать будет только на H2 ))

Речь идет прежде всего о функциональных тестах ;)

Да неважно о каких. Если в тестах используется СУБД и это не ваша целевая СУБД, то сказать, что будет работать с целевой СУБД — нельзя.

SQL намного интереснее, конечно же. Да и более гибкий, благодаря не только простым инструкциям создания и изменения структуры БД, так еще можно бодро тут же и данными тестовыми наполнять.

Liquibase очень мощный инструмент. По мимо описания миграций в yaml, он позволяет еще использовать XML, что в свою очередь позволяет не писать rollback, потому что liquibase сам может откатить такую операцию. А если очень хочется извращений, то можно писать миграции в виде java кода.
Насколько мне известно, форматы XML и YAML абсолютно эквивалентны для Liquibase скриптов. Поэтому rollback SQL будет автоматически создаваться и для YAML во всех случаях, когда это возможно, а невозможно это прежде всего, когда речь идет о работе с данными.
Было бы здорово, почитать про сравнение liquibase с flywaydb. Почему и когда стоит выбрать одно, а не другое? Может flyway лучше
Flyway лучше (удобнее и современнее), но Liquibase бесплатный, проверенный и надежный ;)
Шутка, разумеется, но лишь от части. Вообще есть куда более мощные инструменты от компании RedGate, но это уже совсем-совсем коммерческое ПО.

а flywaydb уже научился делать preconditions? считаю что это по сути единственная киллер-фича в liquibase. Всё остальное, из используемого мною, есть в flywaydb.
Но во flywaydb мне нравится подход к блокировке схемы для её изменения, а не записи флага в отдельную табличку

  • вместо spring.jpa.hibernate.ddl-auto=none рекомендую прописывать spring.jpa.hibernate.ddl-auto=validate
  • вместо yaml лучше xml использовать, а ещё лучше — sql файлы. При этом идеально, чтобы одна миграция на один файл с группировкой миграций по дате из создания в подкаталогах — так не попадёте на конфликты при очерёдности исполнения миграций и уйдёте от "портяночных" файлов миграций
Спасибо! Про best practices постараюсь во второй части написать!
А почему вы считаете, что xml лучше?

покажите пример более-менее сложного SQL запроса внутри миграции и сравните его читабельность с таким же запросом внутри блока CDATA в XML формате


И да, содержимое YAML файла не сильно уступает содержимому SQL файла, а выбирая между "YAML vs SQL" предпочтение отдам последнему, так как валидация и подсветка SQL синтаксиса в той же IDEA однозначно лучше будет + запрос можно выполнить сразу в тестовой БД минуя запуск liquibase

Вы имеете в виду не sql миграции, а ссылки на sql файлы внутри xml, да?


<sqlFile path="file.sql" />

Так?

Если скрипт действительно большой, то его и в самом деле лучше вынести в файл, но если все вынесено в файлы — многовато суеты при анализе кода. Если только IDE не помогает с этим)

многовато суеты будет разгребать портянку в одном XML или разбирать последовательность запуска миграций в нескольких сгрупированных XML — легко можно отхватить ситуацию, когда миграция в одном файле ожидает, что уже выполнилась миграция из другого файла, а это не так.
Плюс, в том же Git, гораздо легче сливать небольшие файлики миграций, чем большие — меньше конфликтов получается

Пожалуй, соглашусь. Взгляните на вторую часть статьи, если не трудно)

смотрел) но
1) я не сторонник описания схемы БД через аннотации Hibernate и автогенераторы — не всё можно прописать или описания через аннотации получается больше чем сама сущность или не всё, что есть в БД надо описывать в сущности. Потому описание миграции руками + validate у Hibernate, что сущность соответствует схеме в минимальном виде
2) как писал уже выше, лучше раскладывать миграции по подкаталогам, а не все в один каталог. Представьте, что у вас по 2-3 миграции в день и вашему проекту уже год и поразгребайтесь в каталоге "db/changelog" после этого. Мы у себя на проекте используем следующую маску: "YYYY/MM/DD_HHmmNNN.xml". Вроде бы как и у вас с timestamp, но уже попроще выглядит содержимое каталога миграций

Благодарю! Кстати, очень интересная идея с использованием даты в имени папок.

А как тогда описать rollback для конкретного sql файла?

согласно документации


но я редко (читай — никогда) пишу rollback — чаще preconditions и то, только в том случае, когда они реально нужны.

А можете чуть подробней про ваш опыт с preconditions? Речь идет о разных скриптах для разных БД?

например, когда добавили что-то "на горячую" в боевой БД, а потом уже написали миграцию, делающую то же самое. Тут пишется preconditions, чтобы миграция пометилась как выполненная, но фактически не выполнялась и то, только если миграция может "упасть" или поломать данные при "повторной" накатке на БД. При этом в остальные окружения эта миграция раскатится в обычном режиме.


Явный пример: когда-то давно в PostgreSQL не было "IF NOT EXISTS" при создание индекса. на проде срочно добавили индекс, а теперь его надо прописать в миграцию. Раньше это решалось только через preconditions. Сейчас обычная миграция c "IF NOT EXISTS"


а "разные скрипты для разных БД" пишутся через "дублирование" changeSet с указанием нужной БД в атрибуте dbms у ChangeSet

Благодарю! Это интересно)
Неужели Flyway ничего такого не поддерживает?

Flyway поддерживает миграции для разных БД через суффиксы в имени файла — считай так же, как и Liquibase, только чуть другой формат
Но у Flyway нет preconditions на миграцию — она либо выполняется либо грохается — пометить её как исполненную не исполняя фактически нельзя
При этом мне больше нравится как у Flyway сделана кластерная миграция — делается LOCK на схему, а не флажком в отдельной табличке в БД.

Я лично против того, чтобы включать прогон ликви скриптов при старте приложения. Мне кажется это шаг нужно включать в CI отдельно, до непосредственно запуска приложения. Скрипты бывает выполняются долго, удобно сразу понять, что проблема возникла при миграциях, а не из-за приложения и ещё можно сделать отдельный сервер для тестирования миграций на живых данных.

Вполне разумная мысль. Думал об этом. На всякий случай напишу, что можно отключить liquibase опцией
spring.liquibase.enabled=false
Ну или просто не подключать зависимость liquibase-core.
Sign up to leave a comment.

Articles