Создание базового состояния существующей базы данных в Prisma без выполнения команды migrate reset
Узнайте, почему Prisma фиксирует отклонения в существующей базе данных, почему сброс миграций — неверное решение, и как установить базовый уровень с помощью db pull, migrate diff и migrate resolve.
Prisma Migrate работает с базой данных, в которой уже есть таблицы и данные, и с высокой вероятностью первая команда npx prisma migrate dev завершится предупреждением о несоответствии структуры и предложит сбросить всё. Это сообщение означает, что в базе данных присутствует структура, о которой миграционная история Prisma ничего не знает. Если согласиться на сброс, данные будут удалены. В этом руководстве объясняется, почему возникает конфликт, почему сброс практически никогда не является правильным решением для важной базы данных, и как задать основу существующей схемы, чтобы Prisma использовал её в качестве отправной точки и применял изменения только относительно неё.
Почему Prisma обнаруживает конфликт
Prisma Migrate хранит две записи о развитии вашей схемы: файлы миграций в папке prisma/migrations и таблицу с названием _prisma_migrations внутри базы данных, которая указывает, какие из этих файлов были применены. При запуске команды migrate dev Prisma воспроизводит историю миграций в временной базе данных и сравнивает результат с реальной базой.
Если в реальной базе данных уже существуют таблицы, которые не были созданы в ходе миграций — например, потому что она была создана вручную, с помощью другого инструмента или более ранней версии приложения — данные двух баз не совпадают. Prisma называет это отклонением. Поскольку команда migrate dev предназначена для разработки, её стандартным решением является полное очистка базы данных и её пересоздание на основе истории миграций, поэтому она предлагает сброс. Это разумно для временной локальной базы данных, но разрушительно для любых других случаев.
Если вы хотите узнать больше о том, как база данных shadow участвует в этом сравнении, ознакомьтесь с базой данных shadow Prisma и проблемами с названиями.
Почему команда migrate reset — неправильное решение
npx prisma migrate reset удаляет базу данных или все таблицы в её схеме, создаёт их заново на основе ваших миграций и запускает скрипты для заполнения данных. Все существующие строки теряются. В базе данных с реальными пользователями, заказами или контентом это не разрешение конфликтов, а потеря данных.
Лучший подход — не трогать базу данных, а вместо этого обновить представление Prisma о структуре данных. Для этого необходимо зафиксировать текущую структуру в виде первой миграции и сообщить Prisma, что эта миграция уже применена.
Шаги по созданию исходной точки
Шаг 1: Изучение существующей базы данных
Запустите команду npx prisma db pull. Prisma подключается к базе данных, считывает её таблицы, столбцы, индексы и связи, а затем записывает соответствующие модели в файл schema.prisma. После этого шага файл схемы точно описывает состояние базы данных.
Шаг 2: Создание исходной миграции без её применения
Создайте папку для базовой конфигурации, например prisma/migrations/0_init. Префикс 0_ позволяет ей отсортироваться раньше всех последующих миграций с указанием даты. Затем сгенерируйте SQL-код, который создаст текущую схему из ничего, и сохраните его там с помощью команды npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script > prisma/migrations/0_init/migration.sql. В новых версиях Prisma параметр целевой схемы может называться --to-schema, поэтому проверьте документацию к вашей версии с помощью команды npx prisma migrate diff --help.
Этот шаг важен, поскольку он создаёт файл миграции без изменения базы данных. Распространённой ошибкой является выполнение команды npx prisma migrate dev --name baseline на этом этапе. В случае базы данных, уже содержащей таблицы и не имеющей истории миграций, эта команда обнаруживает ту же отклонение, что и ранее, и требует повторной сброса, чего вы как раз и пытаетесь избежать. SQL-код базового состояния никогда не следует выполнять в отношении существующей базы данных, поскольку её таблицы уже существуют.
Шаг 3: Означить базовое состояние как применённое
Выполните команду npx prisma migrate resolve --applied 0_init. Аргументом является имя папки с миграциями. Если папка была создана с временной меткой, например 20250101120000_baseline, необходимо указать полное её имя, а не просто baseline.
Эта команда не выполняет никаких SQL-запросов к вашим таблицам. Она вставляет строку в _prisma_migrations, указывающую на то, что базовая конфигурация применена. По сути, вы изменяете внутренние записи Prisma так, чтобы он считал текущую структуру намеренной и корректной.
Как это решает конфликт
Это похоже на конфликт слияния в Git: когда у вашей ветки отсутствуют коммиты, уже присутствующие в основной ветке, вы обновляете свою ветку вместо того, чтобы удалять основную. Здесь база данных находится в более новом состоянии, и вы приводите историю Prisma в соответствие с ней.
После записи базовой конфигурации следующая команда npx prisma migrate dev повторяет выполнение скрипта 0_init в теневой базе данных, получает такую же структуру, как и в реальной базе, и не обнаруживает отклонений. С этого момента, когда вы изменяете файл schema.prisma, Prisma генерирует новую миграцию, содержащую только различия, и применяет именно их.
Почему это важно для крупных баз данных
Основная выгода от использования базового состояния проявляется тогда, когда в базе данных хранится большое количество данных. Поскольку базовое состояние записывается в _prisma_migrations, а схема соответствует действующей базе данных, Prisma не трогает существующие таблицы и строки, а применяет только новые изменения, благодаря чему таблица users остается нетронутой.
Учитывайте следующие практические моменты:
- Выполните команду
migrate resolve --appliedпо крайней мере один раз для каждой существующей среды, такой как стадионная и производственная, поскольку у каждой базы данных есть своя таблица_prisma_migrations. - В производственной среде применяйте более поздние миграции с помощью команды
npx prisma migrate deploy, а неmigrate dev, предназначенной исключительно для разработки. - Загрузите папку с базовым состоянием в систему контроля версий, чтобы все разработчики и задачи CI использовали одну и ту же отправную точку.
Основные выводы
- Предупреждение о смещении в существующей базе данных означает отсутствие истории миграций Prisma, а не ошибку в самой базе данных.
- Сброс удаляет данные; рассматривайте этот инструмент только как средство для временных локальных баз данных.
- Определение исходного состояния осуществляется путем анализа с помощью
db pull, генерации SQL-кодов с помощьюmigrate diff --from-emptyи записи результата с помощьюmigrate resolve --applied. - Не используйте
migrate devдля создания исходного состояния на уже заполненной базе данных, так как это вызовет тот же запрос на сброс. - После установления исходного состояния Prisma обрабатывает только дополнительные изменения, при этом существующие данные остаются нетронутыми.