Миграция схемы базы данных Room в Android

Пользователь обновил приложение — и при первом запуске видит белый экран или крэш. В Logcat: `IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number`. Или хуже: `Migration didn't properly handle` с потерей всех локальных

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Миграция схемы базы данных Room в Android
Средний
~2-3 дня

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    597

Пользователь обновил приложение — и при первом запуске видит белый экран или крэш. В Logcat: IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. Или хуже: Migration didn't properly handle с потерей всех локальных данных. Это классика неправильно реализованной миграции Room. Наш опыт — 7+ лет в Android-разработке, более 30 проектов с миграциями разной сложности. Мы поможем избежать таких ситуаций. В этой статье разберем, как правильно выполнить миграцию схемы базы данных Room, какие типы изменений бывают и как их тестировать.

По статистике, около 30% проектов сталкиваются с ошибками миграции, приводящими к потере данных. Своевременное тестирование снижает этот риск на 80%. Правильная миграция экономит до 50% времени на отладку.

Room миграция: как избежать ошибок?

Как Room определяет необходимость миграции?

Room хранит хэш схемы базы данных. При каждом запуске сравнивает хэш скомпилированного @Database с хэшем, хранящимся в room_master_table. Если они не совпадают — Room бросает исключение, если не найдена подходящая миграция. version в @Database — это контракт: если схема изменилась, version должен быть увеличен, и добавлена явная Migration(fromVersion, toVersion). Room управляет версионированием автоматически, но только при условии корректно описанных переходов.

Типы изменений и их миграция

Добавление колонки (простой случай)

val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL("ALTER TABLE transactions ADD COLUMN category TEXT NOT NULL DEFAULT ''") } } 

NOT NULL DEFAULT '' — обязательно. SQLite не позволяет добавить NOT NULL колонку без DEFAULT в уже существующую таблицу с данными.

Переименование колонки

SQLite не поддерживает ALTER TABLE RENAME COLUMN до версии 3.25.0. На Android API < 29 это недоступно. Универсальный путь — пересоздание таблицы:

val MIGRATION_2_3 = object : Migration(2, 3) { override fun migrate(db: SupportSQLiteDatabase) { db.execSQL(""" CREATE TABLE transactions_new ( id TEXT NOT NULL PRIMARY KEY, amount REAL NOT NULL, description TEXT NOT NULL DEFAULT '', created_at INTEGER NOT NULL ) """) db.execSQL(""" INSERT INTO transactions_new (id, amount, description, created_at) SELECT id, amount, note, created_at FROM transactions """) db.execSQL("DROP TABLE transactions") db.execSQL("ALTER TABLE transactions_new RENAME TO transactions") } } 

Добавление таблицы с внешним ключом

Создайте таблицы через CREATE TABLE IF NOT EXISTS. Внешние ключи включаются после завершения миграции — Room управляет foreign_keys автоматически.

Что такое цепочки миграций и как их использовать?

Room может применять миграции последовательно. Если пользователь перескочил с версии 1 на 4, Room выполнит MIGRATION_1_2, затем MIGRATION_2_3, затем MIGRATION_3_4 — при условии, что все они зарегистрированы.

Room.databaseBuilder(context, AppDatabase::class.java, "app.db") .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4) .build() 

Для ускорения можно добавить прямой Migration(1,4), выполняющий все изменения за один проход.

Тестирование миграций через MigrationTestHelper

Каждую миграцию необходимо тестировать. Room предоставляет MigrationTestHelper для JUnit. Инструмент позволяет автоматизировать проверку в 10 раз быстрее, чем ручное тестирование. Пример для миграции 1→2:

@RunWith(AndroidJUnit4::class) class MigrationTest { @get:Rule val helper = MigrationTestHelper( InstrumentationRegistry.getInstrumentation(), AppDatabase::class.java ) @Test fun migrate1To2() { helper.createDatabase(TEST_DB, 1).apply { execSQL("INSERT INTO transactions VALUES ('id1', 100.0, 'test', 1700000000)") close() } val db = helper.runMigrationsAndValidate(TEST_DB, 2, true, MIGRATION_1_2) val cursor = db.query("SELECT category FROM transactions WHERE id = 'id1'") assertTrue(cursor.moveToFirst()) assertEquals("", cursor.getString(0)) } } 

Без тестов вы рискуете потерять пользовательские данные. Мы всегда включаем тесты в объем работ.

Экспорт JSON-схем для валидации

Добавьте в build.gradle аннотацию:

android { defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments += ["room.schemaLocation": "$projectDir/schemas".toString()] } } } } 

Room генерирует schemas/1.json, schemas/2.json — снимки схемы каждой версии. Эти файлы нужно коммитить в репозиторий. Без них MigrationTestHelper не сможет валидировать миграции.

Тип изменения Описание Риск потери данных Необходимость теста
Добавление колонки ALTER TABLE ADD COLUMN Низкий Да
Переименование колонки Пересоздание таблицы Средний Обязателен
Добавление таблицы CREATE TABLE Низкий Да
Удаление колонки Пересоздание таблицы Высокий Обязателен
Destructive migration Database.delete() Полная Нет (не для production)

Сравнение стратегий миграции

Стратегия Скорость Надёжность Сложность
ALTER TABLE ADD COLUMN Мгновенно Высокая Низкая
Пересоздание таблицы Средняя Высокая Средняя
Destructive migration Мгновенно Низкая Нулевая

Как избежать потери данных при миграции?

Всегда тестируйте каждую миграцию на реальных или синтетических данных. Используйте полный набор кейсов: пустые таблицы, записи с NULL, дубликаты. Обязательно проверяйте индексы и триггеры после миграции. Дополнительно рекомендуем делать резервное копирование перед обновлением.

Fallback на destructive migration

В крайнем случае — только для debug-сборок или при явном согласии пользователя: fallbackToDestructiveMigration() стирает все данные. В production это недопустимо.

Миграция схемы Room: пошаговая настройка

  1. Определите изменения схемы и увеличьте version в @Database.
  2. Напишите объект Migration с SQL-командами.
  3. Зарегистрируйте миграцию в addMigrations().
  4. Настройте экспорт JSON-схем в build.gradle.
  5. Создайте JUnit-тест с MigrationTestHelper.
  6. Запустите тест и убедитесь в корректности.

Что входит в работу

  • Аудит текущей схемы и истории версий
  • Написание Migration объектов для всех изменений
  • Тесты через MigrationTestHelper для каждой миграции
  • Настройка экспорта JSON-схем
  • Обработка edge cases: пустые таблицы, внешние ключи, индексы, триггеры

Сроки

1–2 простые миграции (добавление колонок): 0,5–1 день. Сложная реструктуризация с полным покрытием тестами: 2–3 дня. Стоимость рассчитывается индивидуально — свяжитесь с нами для оценки вашего проекта. Получите консультацию по миграции Room уже сегодня. Закажите детальный аудит базы данных.