Для чего нужна миграция в базах данных?android-17

Миграция баз данных - это процесс обновления структуры базы данных при изменении требований приложения без потери существующих данных.

Основные причины необходимости миграции

  1. Изменение схемы БД:

    • Добавление/удаление таблиц
    • Изменение структуры существующих таблиц
    • Модификация типов данных колонок
  2. Сохранение пользовательских данных:

    • Предотвращение потери данных при обновлении приложения
    • Поддержка целостности данных между версиями
  3. Обеспечение бесперебойной работы:

    • Избежание крашей приложения из-за несоответствия схемы
    • Корректное обновление для всех пользователей

Как работает миграция в Room

// Пример миграции с версии 1 на 2
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE users ADD COLUMN last_login INTEGER")
    }
}

// Применение миграции
Room.databaseBuilder(context, AppDatabase::class.java, "database-name")
    .addMigration(MIGRATION_1_2)
    .build()

Типы изменений, требующих миграции

1. Простые изменения

  • Добавление новой таблицы
  • Добавление новой колонки (NULLABLE или с DEFAULT значением)

2. Сложные изменения

  • Удаление колонки/таблицы
  • Изменение типа колонки
  • Добавление ограничений (CONSTRAINTS)

Стратегии миграции

  1. Последовательные миграции:

    • Для каждого изменения версии (1→2, 2→3 и т.д.)
    • Room автоматически выполняет цепочку миграций
  2. Прямая миграция:

    • Пропуск промежуточных версий (1→3)
    • Требует ручного описания всех изменений
// Прямая миграция с 1 на 3
val MIGRATION_1_3 = object : Migration(1, 3) {
    override fun migrate(database: SupportSQLiteDatabase) {
        // Все изменения от 1 до 3
    }
}

Обработка сложных случаев

Изменение первичного ключа

override fun migrate(database: SupportSQLiteDatabase) {
    // 1. Создать временную таблицу
    database.execSQL("CREATE TABLE users_new (...)")

    // 2. Скопировать данные
    database.execSQL("INSERT INTO users_new SELECT * FROM users")

    // 3. Удалить старую таблицу
    database.execSQL("DROP TABLE users")

    // 4. Переименовать новую таблицу
    database.execSQL("ALTER TABLE users_new RENAME TO users")
}

Автоматическая миграция

// В AutoMigration указываем измененные таблицы
@Database(
    version = 2,
    entities = [User::class],
    autoMigrations = [
        AutoMigration (from = 1, to = 2)
    ]
)
abstract class AppDatabase : RoomDatabase()

Преимущества:

  • Room сам определяет изменения схемы
  • Подходит для простых случаев (добавление/удаление колонок)

Ошибки при миграции и их предотвращение

  1. Не указана миграция:

    • Приведет к IllegalStateException
    • Решение: всегда увеличивать version и добавлять миграцию
  2. Несовместимые изменения:

    • Например, изменение типа колонки без преобразования данных
    • Решение: ручная миграция с преобразованием данных
  3. Потеря данных:

    • При неправильном написании миграции
    • Решение: тестирование миграций на реальных данных

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

@Test
fun testMigration1To2() {
    val helper = MigrationTestHelper(
        InstrumentationRegistry.getInstrumentation(),
        AppDatabase::class.java
    )

    // Открываем БД версии 1
    val db = helper.createDatabase("test", 1)

    // Заполняем тестовыми данными
    db.execSQL("INSERT INTO users (...) VALUES (...)")
    db.close()

    // Проверяем миграцию
    helper.runMigrationsAndValidate("test", 2, true, MIGRATION_1_2)

    // Проверяем данные после миграции
    val migratedDb = Room.databaseBuilder(...).build()
    // Assert проверки
}

Резюмируем:

Миграции в Room необходимы для безопасного изменения структуры базы данных между версиями приложения. Они позволяют:

  • Сохранять пользовательские данные при обновлении
  • Поддерживать целостность базы данных
  • Обрабатывать сложные структурные изменения
  • Обеспечивать стабильную работу приложения

Правильно реализованные миграции - критически важный компонент для любого приложения, работающего с локальным хранилищем данных.