JavaRush /Java блог /Java-проекты /SpringBoot + Flyway - "Java-проект от А до Я"
Roman Beekeeper
35 уровень

SpringBoot + Flyway - "Java-проект от А до Я"

Статья из группы Java-проекты
Статья из серии о создании Java-проекта (ссылки на другие материалы — в конце). Ее цель — разбор ключевых технологий, итог — написание телеграм-бота. В этой части пробуем запустить SpringBoot и к нему — Flyway. Минимальное количество теории, как вы любите))) Итоговое сравнение Flyway/Liquibase опускаем на неопределенное время и переходим к сути. А то и так уже он затянулся. Чтобы дважды не описывать Flyway, решил его сразу добавлять в наш будущий проект JRTB."Java-проект от А до Я": SpringBoot + Flyway - 1

Что в рамках этого нам нужно сделать?

  1. Запустить SpringBoot приложение на базе Maven.
  2. Добавить туда Flyway: благо, они легко интегрируются.
  3. Добавить схему таблиц, которые есть у нас в примере базы данных.
Таким образом мы научимся работать с Flyway. Почему отдельным проектом, а не сразу в наш JRTB? Потому что позже любой, кто захочет понять, как это сделать, будет иметь проект с примером и статью, которая описывает работу с ней. Ну что ж, поехали!

Что такое flyway

Чтобы что-то использовать, нужно для начала выяснить, что это такое и зачем. Flyway — это инструмент для контроля версии базы данных. Слова известные, но как-то понимания не добавилось, да? Попробуем описать проблему, которую решает flyway. Допустим, у нас есть проект. Как и все в нашем мире, он не совершенен, поэтому спланировать и составить окончательную версию проекта не получилось. Каждый раз появляются те или иные неучтенные нюансы. Проект в своей работе использует БД. Разумеется, при изменении проекта может измениться и структура базы данных. Допустим, мы добавляем новое поле для одной из сущностей нашего проекта. Как это сделать?
  1. Добавить это поле в нашу сущность, обновить все, чтобы бизнес логика работала.
  2. Обновить базу данных. Единственный возможный способ — сделать это вручную. Для этого нужно зайти и прописать необходимый sql скрипт.
Из второго пункта возникает много вопросов:
  1. а если у нас не одно место, где мы разворачиваем наш проект, то это в каждом из них нужно делать?
  2. а если мы захотим вернуться назад, как мы узнаем, в каком именно состоянии сейчас находится структура БД?
  3. как мы будем уверены, что изменение БД прошло успешно?
  4. как получить возможность отследить все изменения БД, которые прошли на проекте?
Если делать руками, то ответы будут не лучшие… Чтобы избежать всех этих трудностей, можно воспользоваться инструментом для миграции БД. Одним из таких и является Flyway. В чем заключается его работа? В рамках проекта мы храним отдельные sql файлы (так называемые миграции), которые хранят в себе все то, что мы делаем с БД за один раз. Все миграции идут строго в определенном порядке, что позволяет отследить изменения в структуре и данных БД (часто при помощи миграции добавляют тестовые данные в проект, чтобы при разворачивании его на какой-то сервер он уже имел какие-то значения, при помощи которых можно тестировать проект). После того, как пройдут тесты, при сборке проекта запускаются миграции. Они соединяются с базой данных и проводят миграции. Если миграции уже были проведены на этой базе данных, то flyway их просто пропустит (у него в БД в отдельной таблице хранятся данные о миграциях, об их состоянии, что помогает управлять ими), а если какая-то миграция прошла неуспешно, то сборка проекта и его монтирование (деплой) на сервер остановятся. Я постарался описать как можно подробнее. Если все еще не до конца ясно — не беда: в практике придет и понимание.

Запускаем SpringBoot + Flyway

Что такое Spring Boot

А что же такое запускаем?... Чтобы понять, что и зачем мы делаем, нужно определиться с тем, что такое SpringBoot. Вначале быстро поговорим (ну ооочень быстро) о Spring. На данный момент это де-факто промышленный стандарт в разработке серверных приложений на Java. Стандарт чего? Как вам так объяснить. Spring — это скелет приложения, на который мы потом набрасываем “мясо” — нашу бизнес-логику. При помощи спринга (здесь и далее буду использовать эту кальку, чтобы не тратить время на переключение языка :D )) Спринг дает нам старт, с которого мы начинаем все делать. Он многоликий многомодульный:
  1. Хочешь работать с базой данных? Хочешь с реляционной? Хочешь с нереляционной? Вот, пожалуйста, у нас Spring Data.
  2. Хочешь работать с http запросами? Вот тебе, пожалуйста, Spring web (Spring MVC).
  3. Тебе нужен контейнер для всех объектов в одном месте? Вот Spring Core.
  4. Нужно настроить безопасность на проекте, да так, чтобы были разные роли и субординация? Spring Security.
  5. Ты только подумал о том, что хорошо бы иметь такую штуку, так окажется, что у Спринга уже есть то, что тебе нужно, и оно быстро и легко интегрируется.
Поэтому можно сказать, что это не просто фреймворк (такая бооольшая библиотека), а уже целая экосистема, которая развивается бешеными темпами. Чтобы понять, что из себя представляет Spring Core, то есть база, к которой подключаются модули, советую посмотреть живое демо по созданию собственного фреймворка. Ведет его Евгений Борисов, очень крутой чувак в области Java и спринга. Проделайте все то, что он сделал, и работа спринга вам станет более понятной. SpringBoot, в свою очередь, — это вершина всего того, что у них есть. Магия чистой воды. Минимум настроек для того, чтобы сделать первый запуск приложения. Разумеется, это не даст вам понимания, как им пользоваться и что нужно делать. Но перед тем, как бросаться в глубь разработки, нужно посмотреть на все с высоты птичьего полета.

Запускаем SpringBoot

Так как мы уже разбирались в том, что такое мавен, давайте создадим новый проект для наших нужд. Для этого просто нужно перейти на сайт, специально созданный для этого дела. Называется он Spring Initializr."Java-проект от А до Я": SpringBoot + Flyway - 2Здесь нужно заполнить и выбрать необходимое:
  1. Инструмент по сборке проекта — gradle или maven. Как видите, об Ant уже и не вспоминают. Это хорошая подсказка о том, каким средствам сборки стоит уделить время.
  2. Язык, на котором можно писать — java, kotlin, groovy. Здесь все просто: все они JVM подобные и спокойно запускают Java код. К слову, стоит посмотреть и на Котлин. Груви уже откровенно стал неинтересным (было время, когда на груви переходили, но оно быстро прошло).
  3. Версию спринга… Здесь нужно понимать, что версии главной части спринга и его модулей согласованы.
  4. Данные о проекте. Я уже описывал эти вещи.
  5. Выбираем, в какой архив будет собираться — Jar или War.
  6. Ну и версию джавы нашей любимой. А то в последнее время развелось этих версий… много) То ждали годами, а теперь по две в год.
В нашем случае будем публиковать этот проект в организации JavaRush Community, поэтому и данные о проекте будут соответствующие:
  1. Maven — не зря же мы говорили с вами об этом ранее.
  2. Java — наша родимая :D
  3. Версию возьмем 2.2.11. Почему не самую новую? Потому что чем новее, тем больше шансов, что там могут быть какие-то косяки. Для нас не принципиально, какая именно версия, а более старая будет надежнее. Поэтому выбираем 2.2.11.
  4. Group: com.github.javarushcommunity
  5. Artifact: springboot-flyway-demo
  6. Name: SpringBoot + Flyway Demo
  7. Description: Project demonstrates integration between SpringBoot and Flyway. (Да, умение писать документацию — это важная часть разработки:))
  8. Package name: com.github.javarushcommunity.springbootflywaydemo. Здесь за нас сразу же создадут базовый пакет с классом, который запустит наше приложение.
  9. Packaging: Jar
  10. Java: 8. Не будем идти впереди паровоза и возьмем старую добрую восьмерку. Почему не 11? А зачем? Для нашего примера не вижу смысла.
"Java-проект от А до Я": SpringBoot + Flyway - 3А теперь добавим модули. Нам нужно найти интеграцию с Flyway. Можно еще добавить что-то связанное с MySQL и Spring Data. Добавим еще ломбок (это очень нужная вещь, просто поверьте пока что :D)) Для этого дела нажимаем на ADD DEPENDENCIES… и выберем все, что нужно:"Java-проект от А до Я": SpringBoot + Flyway - 4Вот так добавим Flyway."Java-проект от А до Я": SpringBoot + Flyway - 5Ломбок… И так далее. В итоге получим:"Java-проект от А до Я": SpringBoot + Flyway - 6Хух… заполнили все)) Теперь жмем GENERATE… и все — архив со сгенерированным проектом готов :) Там еще есть такая крутая штука как SHARE…, которая дает вам ссылку на страницу, которую вы только что заполнили. То есть, вот та, которую я генерировал. И даже если у вас что-то пойдет не так, всегда можно будет проверить по ссылке. Далее нам нужно привязать созданный проект к гит репозиторию, поэтому клонируем созданный проект springboot-flyway-demo и качаем его через IDEA. Для этого, нужно открыть идею и выбрать File -> New -> Project from Existing Sources…:"Java-проект от А до Я": SpringBoot + Flyway - 7Теперь добавляем URL и нажимаем Clone. Следующим шагом нужно перенести внутренности сгенерированного проекта внутрь того, что мы клонировали. Запутал? Сейчас покажу. Разархивировал и получил такой набор файлов:"Java-проект от А до Я": SpringBoot + Flyway - 8Вот их и нужно перенести в клонированный проект. Как и в прошлой статье, добавим pom.xml как мавен проект:"Java-проект от А до Я": SpringBoot + Flyway - 9Теперь нам интересно посмотреть на то, что нам сгенерировали. Если открыть все папки в src и далее, то будет видна обычная иерархия в мавен проектов, которую мы разбирали в предыдущей статье. Кто не читал — почитайте!"Java-проект от А до Я": SpringBoot + Flyway - 10Видно, что у нас есть Application класс, и при помощи него запустится наше SpringBoot приложение. Благодаря плагину в мавене для SpringBoot, у нас появился нужный нам таск для мавена, а именно — spring-boot:run. Где мы можем найти эту информацию? Справа, открыв плашку Maven и наш проект:"Java-проект от А до Я": SpringBoot + Flyway - 11Будет ошибка, и ее так мы не сможем прочесть, увидим что-то такое:"Java-проект от А до Я": SpringBoot + Flyway - 12Чтобы получить больше информации, для быстроты мы можем запустить main метод Application классе:"Java-проект от А до Я": SpringBoot + Flyway - 13И тогда уже увидим реальную причину:"Java-проект от А до Я": SpringBoot + Flyway - 14Здесь уже информации поболее и можно с ней что-то делать. Что не так? У нас есть зависимости, связанные с БД, и поэтому нужно предоставить настройки для подключения к оной. Для этого дела гуглим, находим, что нужно добавить следующие конфигурации в application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/flyway_demo_db
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
Запускаем еще раз main метод и получаем:"Java-проект от А до Я": SpringBoot + Flyway - 15Теперь нужно добавить хотя бы одну миграцию. Чтобы правильно составить миграцию, нужно взять следующий шаблон: V<VERSION>__<NAME>.sql Руководствуясь им, создадим файл миграции с именем V00001__Create_country_table.sql в соответствующей папке: /src/main/resources/db.migration/. В ней создадим таблицу country. Скрипт возьмем из второй статьи о БД."Java-проект от А до Я": SpringBoot + Flyway - 16Перед запуском зайдем и создадим БД для работы: flyway_demo_db. Сделаем это через MysqlWorkbench:"Java-проект от А до Я": SpringBoot + Flyway - 17Теперь-то можно запустить еще раз main метод:"Java-проект от А до Я": SpringBoot + Flyway - 18Все получилось, но так как у нас ничего еще нет в проекте, он закончил работу. Однако видно из логов (что такое логи — вот почитайте), что:
  1. Успешно подключились к БД.
  2. Прошла валидация миграции и с ней все ок.
  3. Flyway создал таблицу для управления миграциями.
  4. И то, что начала миграция 00001 — создание country прошла успешно.
Чтобы это проверить, можно сходить и посмотреть, что делается в БД. Так что зайдем на наш MySQL сервер и посмотрим, что там с таблицами в бд flyway_demo_db: $ USE flyway_demo_db; $ SHOW TABLES;"Java-проект от А до Я": SpringBoot + Flyway - 19Как я и ожидал, прошла миграция, в ходе которой создалась таблица country и появилась таблица flyway_schema_history, которая хранит информацию по миграциям. Пойдем дальше и посмотрим какие там есть записи (и есть ли вообще они). $ SELECT * FROM flyway_schema_history;"Java-проект от А до Я": SpringBoot + Flyway - 20Вот и запись, одна-единственная. В ней — много интересных данных. Версия, описание миграции, какой тип SQL (и, может быть, еще XML), имя самого скрипта, чексумма (это что-то типа hashcode, при помощи которого проверяется, изменилась или нет миграция. Делается это на случай, если мы провели миграцию в БД и потом ее поправили: делать этого нельзя, все правки вносятся только посредством новой миграции и чтобы этого не было, чек сумма следит за этим), имя sql юзера, дата обработки миграции, время на выполнение и результат (успешно или не успешно). Миграция, написанная один раз, не должна быть изменена будущем. Даже если в ней находится дефект. Все изменения проходят только посредством новой миграции. Это очень важно. Чтобы показать, что будет, давайте немного изменим наш скрипт и попробуем запустить его вновь. Добавим в нашу миграцию одну запись в таблицу country:"Java-проект от А до Я": SpringBoot + Flyway - 21и запустим main метод и вот что получим:"Java-проект от А до Я": SpringBoot + Flyway - 22Как я и ожидал, flyway распознал, что скрипт был изменен и не провел миграцию. В некоторых случаях действительно бывает необходимо запустить обновленную миграцию и чтобы flyway это пропустил, нужно удалить запись в таблице flyway_schema_history и уже после этого накатить обновленную миграцию. Это не нормальное поведение и так не должно быть, но знать о таком способе разрешения проблемы также нужно. Разобрались с первой миграцией. Теперь хотелось бы добавить еще одну миграцию, с данными о странах, как было в статье о БД: файл V00002__Add_test_data_to_country.sql"Java-проект от А до Я": SpringBoot + Flyway - 23И запустим опять main метод:"Java-проект от А до Я": SpringBoot + Flyway - 24Из логов видно, что перед началом запуска миграции БД была в версии 00001, поэтому запустятся все миграции после этой версии. Далее, запустилась версия 00002 и прошла успешно. Проверим, или уже верите мне, что три записи в country будут уже находится в БД?)) Я бы проверил, поэтому пруф:"Java-проект от А до Я": SpringBoot + Flyway - 25Вот как-то так. Если запустить еще раз проект, то flyway просто пропустит накатывание миграций, так как база данных полностью соответствует необходимой версии.

Вывод

В этот раз мы научились худо-бедно понимать и использовать инструмент для миграции БД в связке со SpringBoot. Эта информация необходима для понимания того, что такое инструмент контроля версий баз данных на примере Flyway. Друзья, исходники проекта, который я показал, опубликованы у нас в организации на гитхабе. Если вам нравится пример, ставьте ему звезду, и я буду понимать, что моя работа полезна и ее реально стоит продолжать. Традиционно предлагаю подписаться на мой гитхаб аккаунт. Через него я веду всю свою работу по open source и все те демо проекты, которые неизменно сопровождают мои статьи. Всем спасибо за прочтение. В следующий раз уже будем писать наше приложение. Будет еще в будущем необходимая теория по докеру, но мы ее густо разбавим практикой.

Полезные ссылки

Сегодня не так уж и много полезных ссылок. Обратите внимание на видео Евгения, оно действительно стоит того!
  1. Сайт для создания проектов на спринге
  2. Евгений Борисов — Spring-построитель
  3. Документация в спринге по Flyway

Список всех материалов серии в начале этой статьи.

Комментарии (50)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Anonymous #2856674 Уровень 18
1 марта 2024
Вот тут "Далее нам нужно привязать созданный проект к гит репозиторию, поэтому клонируем созданный проект springboot-flyway-demo и качаем его через IDEA. Для этого, нужно открыть идею и выбрать File -> New -> Project from Existing Sources…:" Как понимаю опечатка, надо выбирать Project from Version Control
Артём Журкин Уровень 17 Expert
9 февраля 2022
Как цикл, описывающий процесс создания приложения пойдет, но при детальном рассмотрении похоже на бормотание себе под нос. Новичкам рекомендация, выписать все что здесь используется и учить на более вразумительных источниках, здесь нормальных знаний не получите, все по галопом по верхам
Иван Сергеевич Уровень 41
13 сентября 2021
Накосячил с запросом и потом вылазила ошибка в миграции бд, исправил так: https://stackoverflow.com/questions/44970904/flyway-exception-detected-failed-migration ... через 5 минут: а вообще оказывается дальше по лекции есть решение :D
Филипп Уровень 27
6 августа 2021
Спасибо, но немного не понятно, какой смысл в этой библиотеке если есть spring.jpa.hibernate.ddl-auto=validate / update это же то же самое -проверка / обновление БД к текущей версии программы. Или у flyway есть какие-то дополнительные фишки?
Dmitry Gebeydullov Уровень 18
6 июля 2021
Итак у меня был другой путь.. Идея же может все за нас делать, но мне пришлось долго биться. в общем, удалил все что связано с гитом с компа. Качаем проект с spring init, и ручками его в гит добавляем. В идее жмем create project from VCS
9 июня 2021
В первую очередь . Роман большое спасибо за ваши труды! Нашёл не большую опечатку , с вашего позволения поправлю.

Далее нам нужно привязать созданный проект к гит репозиторию, поэтому клонируем созданный проект springboot-flyway-demo и качаем его через IDEA.
тут вместо ссылки на springboot-flyway-demo должна быть ссылка на шаблон гит репозитория Шаблон для репозитория Ещё раз Роман Огромная Вам Благодарность !
Кирилл C. Уровень 40
1 июня 2021
Ходят упорные слухи, что Ломбок - зло и им пользоваться не нужно. Совсем не нужно.
Khodyachaya Entsiklopedia Уровень 28
13 апреля 2021
Вижу, не только мне это занятие показалось невнятным. Тоже ошибка на ошибке вылазила, когда пытался повторить все действия. Придется забить, пойду дальше.
Leftover Уровень 39
22 марта 2021
Для PostgreSQL оказалось достаточно вот этого:

spring.datasource.url=jdbc:postgresql://localhost:5432/flyway_demo_db
spring.datasource.username=user
spring.datasource.password=password
Документация утверждает, что в большинстве случаев Spring может "распознать" драйер по url.