Room数据库模型意外变更引发数据完整性校验错误排查
错误提示
Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
问题背景
明明没修改过Room实体类,却触发了上述数据完整性校验失败。对比变更前后的数据库结构,发现GridItem表的created_at列从TEXT变成了TEXT NOT NULL。
近期做过的操作包括:
- 为现有Android项目集成KMM模块
- 更新firebase-crashlytics
- 将项目级
build.gradle转为Kotlin DSL格式(build.gradle.kts) - 升级Gradle wrapper版本从6.6.1到7.3.3
- 升级Android Gradle插件版本从4.0.1到7.2.2
- 升级Kotlin版本从1.6.21到1.8.0
- 升级
com.google.gms:google-services从2.2.1到2.9.4
关键补充
之前执行过手动迁移SQL:
database.execSQL("ALTER TABLE `GridItem` ADD COLUMN `created_at` TEXT NOT NULL DEFAULT ''");
但之前导出的数据库里,这个列却只显示TEXT,没有NOT NULL约束,现在升级依赖后Room却识别出了这个约束,导致schema校验不通过。
根本原因分析
旧版本Room的校验漏洞
旧版本Android Gradle插件(4.0.1)搭配Kotlin 1.6.21时,Room在生成schema文件或校验数据库结构时,没有正确识别手动迁移中添加的NOT NULL约束。这导致schema文件里的created_at列定义是TEXT,和实际数据库里的约束不一致,但Room没触发错误。新版本的严格校验
升级到Android Gradle插件7.2.2 + Kotlin 1.8.0后,Room的schema校验逻辑变得更严格,开始正确解析数据库中实际存在的NOT NULL约束,发现它和之前生成的schema文件定义不匹配,因此触发了数据完整性错误。手动迁移与自动schema的冲突
手动执行ALTER TABLE添加带NOT NULL约束的列后,Room自动生成的schema文件并没有同步更新这个约束(因为实体类里没加@ColumnInfo(nullable = false))。旧版本Room忽略了这个不一致,新版本则严格校验,导致错误出现。
解决方案
同步实体类与数据库约束
在GridItem实体类的created_at字段上添加@ColumnInfo(nullable = false),确保Room生成的schema文件和实际数据库结构一致,然后升级数据库版本并编写对应迁移逻辑(如需兼容旧版本)。修正schema文件
如果不想修改实体类,可以手动更新Room的schema文件,将created_at列的nullable属性改为false,然后升级数据库版本,让Room的校验逻辑通过。确认历史数据合规
由于之前添加列时设置了DEFAULT '',现有数据的created_at列应该都有非空值,无需额外处理,但可以做一次数据校验确保没有异常值。
内容的提问来源于stack exchange,提问作者AndreiBogdan

