android.database.sqlite.SQLiteException:无法从游标读取:列 'price' 的类型为 REAL,但应为 INTEGER(代码 0 SQLITE_MISMATCH)
android.database.sqlite.SQLiteException: Cannot read from cursor: column 'price' has type REAL but expected INTEGER (code 0 SQLITE_MISMATCH)
ID: android/room-cursor-mismatch-column-type
版本兼容性
| 版本 | 状态 | 引入 | 弃用 | 备注 |
|---|---|---|---|---|
| Room 2.5.0 | active | — | — | — |
| Room 2.6.0 | active | — | — | — |
| SQLite 3.32.2 | active | — | — | — |
根因分析
Room 实体在 Kotlin/Java 中将列定义为整数类型(例如 Int 或 Long),但由于迁移失败或直接数据库操作,实际的 SQLite 列包含浮点值(REAL)。
English
Room entity defines a column as an integer type (e.g., Int or Long) in Kotlin/Java, but the actual SQLite column contains a floating-point value (REAL) due to a migration failure or direct database manipulation.
官方文档
https://developer.android.com/training/data-storage/room/migrating-dbversions解决方案
-
Create a manual migration in your RoomDatabase class that converts the column type. For example: `val MIGRATION_1_2 = object : Migration(1, 2) { override fun migrate(database: SupportSQLiteDatabase) { database.execSQL("ALTER TABLE products ADD COLUMN price_new INTEGER") database.execSQL("UPDATE products SET price_new = CAST(price AS INTEGER)") database.execSQL("ALTER TABLE products DROP COLUMN price") database.execSQL("ALTER TABLE products RENAME COLUMN price_new TO price") } }` -
Use `@ColumnInfo(typeAffinity = ColumnInfo.REAL)` in your entity to match the actual column type, then handle the conversion in your app logic (e.g., `price.toInt()`).
无效尝试
常见但无效的做法:
-
70% 失败
This only works during development; in production, users lose all local data. The underlying schema mismatch returns when migration is reapplied.
-
85% 失败
Changing the entity type alone does not fix the existing data; Room still reads the column as REAL, and the migration must handle type conversion explicitly.