Android Studio Room数据库迁移报错:表结构不匹配问题排查
Room手动迁移失败的问题排查与修复
1. BOOLEAN类型不匹配问题
SQLite本身没有原生BOOLEAN类型,Room会将实体类中的Boolean字段映射为SQLite的INTEGER类型(0代表false,1代表true)。你在迁移SQL中使用BOOLEAN类型,会导致Room校验表结构时发现实际类型与预期类型不匹配,触发崩溃。
修复方案:
将添加列的SQL语句改为:
ALTER TABLE 'gps' ADD COLUMN 'isTrack' INTEGER NOT NULL DEFAULT 0
2. 外键缺失问题
如果你的Gps实体类中为tripId字段定义了外键约束(比如@ForeignKey注解),Room生成的预期表结构会包含该外键,但手动迁移时仅添加了列和索引,未同步添加外键约束,导致结构校验失败。
由于SQLite的ALTER TABLE不支持直接添加外键约束,需要通过临时表重建表并保留外键:
private val migration2To3: Migration = object: Migration(2,3) { override fun migrate(database: SupportSQLiteDatabase) { Log.i("database", "migration from $startVersion to $endVersion started") // 1. 创建包含外键的临时表(需与实体类列顺序、字段完全一致) database.execSQL(""" CREATE TABLE IF NOT EXISTS gps_temp ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, tripId INTEGER NOT NULL, latitude REAL NOT NULL, longitude REAL NOT NULL, timeMillis INTEGER NOT NULL, isTrack INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(tripId) REFERENCES trip(id) ON DELETE CASCADE ) """.trimIndent()) // 2. 复制原表数据到临时表 database.execSQL(""" INSERT INTO gps_temp (id, tripId, latitude, longitude, timeMillis) SELECT id, tripId, latitude, longitude, timeMillis FROM gps """.trimIndent()) // 3. 删除原表 database.execSQL("DROP TABLE gps") // 4. 重命名临时表为原表名 database.execSQL("ALTER TABLE gps_temp RENAME TO gps") // 5. 添加tripId索引 database.execSQL("CREATE INDEX IF NOT EXISTS `index_gps_tripId` ON `gps` (`tripId`)") Log.i("database", "migration from $startVersion to $endVersion ended") } }
注意:需根据你实际的gps表结构,补全临时表中的所有原有列,确保与实体类字段顺序、定义完全一致。
3. 列顺序问题
Room会严格校验表的列顺序是否与实体类生成的Schema一致。即使你未主动修改列顺序,若临时表创建时列顺序与原表/实体类不一致,也会触发结构不匹配错误。务必保证临时表的列顺序和Gps实体类中字段的顺序完全对应。
额外验证步骤
- 查看
app/build/schemas目录下Room生成的Schema文件,对比版本2和版本3的表结构定义,确认迁移后的表结构与Schema完全匹配。 - 迁移完成后,用SQLite工具查看实际表结构,检查列类型、外键、列顺序是否符合预期。
内容的提问来源于stack exchange,提问作者Michel
相关产品推荐
相关产品推荐

