使用Room持久化存储修改SQLite列数据类型且不丢失数据
嘿,这个场景我之前处理过,在Room里不用删除重建表,同时把UserId列从INTEGER改成TEXT并保留原有数据,核心是靠**Room数据库迁移(Migration)**来实现,毕竟SQLite本身对直接修改列类型的支持有限,得用点迂回的技巧,具体步骤如下:
1. 更新你的实体类
首先把Invoice实体里的UserId字段类型从Integer改成String(Room中String对应SQLite的TEXT类型),比如:
// Kotlin示例,Java写法同理 @Entity(tableName = "Invoice") data class Invoice( @ColumnInfo(name = "UserId") val userId: String, // 从Int改为String @ColumnInfo(name = "InvoiceNumber") val invoiceNumber: String, @ColumnInfo(name = "Amount") val amount: Double, // 原表其他字段完整保留... )
2. 创建Migration迁移类
这是最关键的一步,因为SQLite不允许直接用ALTER TABLE ... ALTER COLUMN修改列类型,我们需要通过临时表中转数据:
// Java版本迁移类,Kotlin写法类似 static final Migration MIGRATION_1_2 = new Migration(1, 2) { @Override public void migrate(@NonNull SupportSQLiteDatabase database) { // 步骤1:将原表重命名为临时表 database.execSQL("ALTER TABLE Invoice RENAME TO Invoice_temp"); // 步骤2:创建新的Invoice表,注意UserId类型为TEXT // 必须完整复制原表的所有字段、约束(主键/外键/索引),不能遗漏! database.execSQL("CREATE TABLE Invoice (" + "UserId TEXT NOT NULL, " + "InvoiceNumber TEXT NOT NULL, " + "Amount REAL NOT NULL, " + // 补充原表的主键或其他约束,比如InvoiceNumber作为主键 "PRIMARY KEY(InvoiceNumber))"); // 步骤3:把临时表的数据导入新表,同时将Integer类型的UserId转为TEXT database.execSQL("INSERT INTO Invoice (UserId, InvoiceNumber, Amount) " + "SELECT CAST(UserId AS TEXT), InvoiceNumber, Amount FROM Invoice_temp"); // 步骤4:删除临时表 database.execSQL("DROP TABLE Invoice_temp"); } };
3. 关联Migration到RoomDatabase
更新数据库版本号(比原版本+1),并在@Database注解中添加迁移规则:
@Database( entities = {Invoice.class}, version = 2, // 版本号从1升级到2 exportSchema = true // 建议开启,方便追踪数据库版本变更 ) public abstract class AppDatabase extends RoomDatabase { public abstract InvoiceDao invoiceDao(); // 暴露迁移规则,初始化Room时需要用到 public static final Migration[] ALL_MIGRATIONS = {MIGRATION_1_2}; }
4. 初始化Room时指定迁移
创建Room数据库实例时,必须添加迁移规则,避免Room自动删表重建(默认无迁移规则时会清空数据):
AppDatabase db = Room.databaseBuilder(context, AppDatabase.class, "your-db-name") .addMigrations(AppDatabase.ALL_MIGRATIONS) .build();
重要注意事项
- 务必完整复制原表的所有字段、约束到新表创建语句中,否则会丢失数据或破坏表结构
CAST(UserId AS TEXT)是保留数据的核心,它会将原整数ID安全转换为字符串类型- 迁移前一定要在测试环境验证,最好备份数据,避免SQL语法错误导致数据丢失
- 如果表存在外键关联,要额外处理外键逻辑,确保迁移后关联关系正常
内容的提问来源于stack exchange,提问作者sneharc
相关产品推荐
相关产品推荐

