You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已发布Room+Kotlin+MVVM应用的SQLite表变更数据保全最佳实践

How to Update Room Database Without Losing Existing Data (Kotlin + MVVM)

Great question! When updating a Room-backed app (especially modifying your schema like adding a new table field), the core goal is to implement proper database migrations—Room requires explicit instructions to map old database schemas to new ones, otherwise it’ll either crash or wipe the user’s data (if you’ve enabled destructive fallback, which you usually don’t want). Let’s walk through the best practices and code examples tailored to your Kotlin/MVVM setup:

1. Understand Room’s Versioning System

First, every Room database has a version number defined in your @Database annotation. Anytime you change your entity classes (add fields, modify tables, etc.), you must increment this version number. Room uses this to detect when a user’s local database is out of date and needs migration.

2. Create a Migration Class for Your Schema Change

For adding a new field to an existing table, you’ll need to write a Migration class that tells Room how to alter the old table to match the new schema.

Example Scenario:

Suppose you have an existing User entity:

@Entity(tableName = "users")
data class User(
    @PrimaryKey val id: Int,
    val name: String
)

You want to add a new optional field email: String? to the users table.

Step 1: Update Your Entity Class

Modify the User entity to include the new field:

@Entity(tableName = "users")
data class User(
    @PrimaryKey val id: Int,
    val name: String,
    val email: String? // New optional field
)

Step 2: Write the Migration

Create a Migration object that runs the SQL ALTER TABLE command to add the new column:

val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        // Add the new "email" column as nullable (since it's optional)
        database.execSQL("ALTER TABLE users ADD COLUMN email TEXT")
    }
}
  • The numbers (1, 2) mean this migration handles upgrading from version 1 to version 2.
  • If your new field is non-nullable, you must set a default value in the SQL command, because existing rows don’t have this value:
    database.execSQL("ALTER TABLE users ADD COLUMN email TEXT NOT NULL DEFAULT 'unknown@example.com'")
    

Step 3: Update Your Database Class

Add the migration to your @Database annotation and increment the version:

@Database(
    entities = [User::class],
    version = 2, // Incremented from 1 to 2
    exportSchema = true // Important! Enables schema generation for debugging/testing
)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao

    companion object {
        // Singleton instance (adjust based on your MVVM setup)
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "app_database"
                )
                .addMigrations(MIGRATION_1_2) // Add your migration here
                // Only use this as a last resort! It wipes data if migration fails
                // .fallbackToDestructiveMigration()
                .build()
                INSTANCE = instance
                instance
            }
        }
    }
}

3. Critical Best Practices

  • Always enable exportSchema: This generates a JSON file of your schema in your build directory, which helps track schema changes and debug migration issues.
  • Test migrations thoroughly: Use Room’s MigrationTestHelper (part of the Room testing library) to test migrations against real old database schemas. You can create a test that creates a version 1 database, inserts test data, runs the migration to version 2, and verifies the data is preserved.
  • Avoid destructive fallback unless necessary: The fallbackToDestructiveMigration() method will wipe the database if a migration is missing or fails. Only use this during development or if you can afford to lose user data (which you almost never can in production).
  • Handle complex migrations: If you’re making more complex changes (like renaming columns, splitting tables), write the appropriate SQL commands in your migrate method. Room supports all standard SQLite operations here.

4. What If You Forget a Migration?

If you push an update without a migration and increment the version, Room will throw an IllegalStateException saying it can’t find a migration from the old version to the new one. This will crash the app for existing users—so always double-check your version number and migrations before releasing.

内容的提问来源于stack exchange,提问作者Thoumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 14:47:35