SQLite 手动升级 → Room Migration
老写法(Java + SQLiteOpenHelper)
java
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 2) {
db.execSQL("ALTER TABLE item ADD COLUMN description TEXT");
db.execSQL("ALTER TABLE item ADD COLUMN category TEXT DEFAULT '其他'");
}
if (oldVersion < 3) {
db.execSQL("ALTER TABLE item ADD COLUMN create_time INTEGER DEFAULT 0");
// 迁移旧数据
db.execSQL("UPDATE item SET create_time = ? WHERE create_time = 0",
new Object[]{System.currentTimeMillis()});
}
}
问题在哪里
版本号和 SQL 全靠自己维护,多版本连续升级逻辑如果写错了顺序会丢数据。升级前无法做校验,升级后无法做验证,也没有编译期安全。最容易线上灾难的代码之一------ALTER TABLE 在 Android 上对 SQLite 的兼容性差异很大。
新写法(Room Migration)
kotlin
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE item ADD COLUMN description TEXT")
db.execSQL("ALTER TABLE item ADD COLUMN category TEXT NOT NULL DEFAULT '其他'")
}
}
val MIGRATION_2_3 = object : Migration(2, 3) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE item ADD COLUMN create_time INTEGER NOT NULL DEFAULT 0")
db.execSQL("UPDATE item SET create_time = ? WHERE create_time = 0",
arrayOf(System.currentTimeMillis()))
}
}
// 构建
val db = Room.databaseBuilder(context, AppDatabase::class.java, "app.db")
.addMigrations(MIGRATION_1_2, MIGRATION_2_3)
.build()
未匹配的版本跳转用 fallbackToDestructiveMigration():
kotlin
Room.databaseBuilder(context, AppDatabase::class.java, "app.db")
.fallbackToDestructiveMigration()
.build()
一句话注意
Migration(startVersion, endVersion) 的版本号必须严格连续 ,不能跳号。Room 会按顺序应用所有匹配的 Migration。比如数据库当前版本是 1,目标版本是 3,Room 会自动依次执行 MIGRATION_1_2 → MIGRATION_2_3。
fallbackToDestructiveMigration() 会删库重建------升级后旧数据全部丢失。只有开发阶段可以用,线上千万不能配。如果线上有用户跳版本更新(比如 1 直接升到 4),确保 1→2、2→3、3→4 的 Migration 全部写好了,Room 会自动串联。
Java Android 老项目迁移系列,持续更新中。