Что делать если забыли добавить поле после миграции в Liquibase
Что проверяют
Знаете ли вы главное правило миграций: применённое не правят, добавляют новое. И понимаете ли механику Liquibase, где журнал DATABASECHANGELOG хранит контрольную сумму каждого changeSet и сверяет её при следующем запуске.
Как отвечать
Первым делом выясните, применялся ли changeSet где-нибудь, кроме вашей машины. Если он уже уехал на стенд или на прод, править его нельзя: контрольная сумма изменится, и приложение упадёт при старте на валидации. Поле добавляется отдельным changeSet:
<changeSet id="add-phone-to-users" author="team">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="users" columnName="phone"/></not>
</preConditions>
<addColumn tableName="users">
<column name="phone" type="varchar(32)"/>
</addColumn>
<rollback>
<dropColumn tableName="users" columnName="phone"/>
</rollback>
</changeSet>Предусловие делает миграцию идемпотентной: там, где колонку уже добавили руками, changeSet просто отметится выполненным. Если же changeSet жил только локально, проще откатить изменение на своей базе и поправить файл. В Spring Boot миграции выполняются при старте приложения, поэтому забытое поле обычно всплывает как ошибка отображения сущности.
Где спотыкаются
Дописывают колонку в уже применённый changeSet. Локально всё хорошо, журнал пустой, а на проде приложение не стартует из-за несовпадения контрольной суммы. Пересчёт сумм и ручная правка журнала это аварийная процедура, а не рабочий приём.
Добавляют поле сразу с ограничением NOT NULL без значения по умолчанию на непустую таблицу. Миграция падает. Порядок такой: сначала колонка допускает NULL, затем отдельный changeSet заполняет данные, и только потом ставится ограничение. На больших таблицах заодно проверяют, не приведёт ли изменение к длительной блокировке.
Забывают про журнал блокировок. Упавший на середине запуск оставляет запись в DATABASECHANGELOGLOCK, и следующий старт бесконечно ждёт освобождения. Лок снимают вручную, но только убедившись, что прежний процесс действительно завершился.