Room Kotlin迁移跨库复制列值后数据库为空问题排查
问题分析与修复方案
1. SQL语法错误(核心问题)
你的两条UPDATE语句都缺少闭合括号,这会直接导致SQL执行失败,触发Room迁移的事务回滚,最终数据库可能被还原到迁移前状态,甚至出现空数据的情况。
- 原迁移代码的UPDATE语句:
正确写法需在末尾补充UPDATE 'Catalogues' SET 'favorite' = (SELECT 'favorite' FROM 'fav' WHERE Catalogues.code = fav.itemCode):UPDATE 'Catalogues' SET 'favorite' = (SELECT 'favorite' FROM 'fav'.FavoriteList WHERE Catalogues.code = fav.FavoriteList.itemCode) - 更新后的迁移代码的UPDATE语句同样存在该问题,修正后:
UPDATE 'CatalogList' SET 'favorite' = (SELECT 'favorite' FROM fav.FavoriteList WHERE CatalogList.code = fav.FavoriteList.itemCode)
2. ATTACH语句的路径空格问题
更新后的代码中,$attachDbPath后多了一个空格:
database.execSQL("ATTACH DATABASE '$attachDbPath ' AS fav")
这会导致数据库路径解析错误,无法正确附加Favorite.db,后续查询自然拿不到数据。需去掉空格:
database.execSQL("ATTACH DATABASE '$attachDbPath' AS fav")
3. 数据库路径的空安全处理
database.path可能为null,直接拼接会引发空指针异常,需要做空安全校验:
val attachDbPath = database.path?.let { File(it).parent?.plus(File.separator)?.plus("Favorite.db") } ?: throw IllegalStateException("无法获取数据库路径")
4. 无匹配数据时的默认值处理
如果CatalogList的code在FavoriteList中找不到对应itemCode,子查询会返回NULL,导致favorite列被设为NULL。若需要默认值(比如false或0),可以用COALESCE函数:
UPDATE 'CatalogList' SET 'favorite' = COALESCE((SELECT 'favorite' FROM fav.FavoriteList WHERE CatalogList.code = fav.FavoriteList.itemCode), 0)
5. 表名与列名的引号规范
SQLite中,单引号用于字符串值,表名/列名建议用反引号(`)或双引号包裹,避免语法歧义:
UPDATE `CatalogList` SET `favorite` = COALESCE((SELECT `favorite` FROM fav.`FavoriteList` WHERE `CatalogList`.`code` = fav.`FavoriteList`.`itemCode`), 0)
修正后的完整迁移代码
private val migration3To4 = object : Migration(3, 4) { override fun migrate(database: SupportSQLiteDatabase) { val attachDbPath = database.path?.let { File(it).parent?.plus(File.separator)?.plus("Favorite.db") } ?: throw IllegalStateException("无法获取数据库路径") database.execSQL("ATTACH DATABASE '$attachDbPath' AS fav") database.execSQL(""" UPDATE `CatalogList` SET `favorite` = COALESCE( (SELECT `favorite` FROM fav.`FavoriteList` WHERE `CatalogList`.`code` = fav.`FavoriteList`.`itemCode`), 0 ) """.trimIndent()) database.execSQL("DETACH DATABASE fav") } }
额外排查点
- 确认
Favorite.db路径正确:打印attachDbPath的值,检查是否与实际数据库文件路径一致。 - 检查字段类型匹配:确保
CatalogList.code和FavoriteList.itemCode的数据类型完全一致,否则匹配会失败。 - 开启Room日志:在数据库构建器中添加日志配置,查看具体SQL执行错误:
.setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
内容的提问来源于stack exchange,提问作者jane
相关产品推荐
相关产品推荐

