You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Room数据库重启数据丢失,如何在单库创建多表?

问题描述

我是Android X Room Database新手,此前使用Sqlitehelper类操作SQLite数据库,现在迁移到Room。目前遇到的问题是:向Room数据库表插入的数据仅临时存储,重启应用后数据丢失。我希望在单个数据库中创建多张表。

我的DAO代码如下:

@androidx.room.Dao
public interface ItineraryDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    void insert(ItineraryData model);

    @Update
    void update(ItineraryData model);

    @Delete
    void delete(ItineraryData model);

    @Query("DELETE FROM "+ CONSTANTS.ITINERARY_TABLE)
    void deleteAllItinerary();

    @Query("SELECT * FROM "+CONSTANTS.ITINERARY_TABLE+" ORDER BY Date ASC")
    LiveData<List<ItineraryData>> getAllItinerary();
}

Database代码如下:

@Database(entities = {ItineraryData.class},version = 1,exportSchema = false)
public abstract  class ItineraryDatabase extends RoomDatabase {

    private static ItineraryDatabase instance;
    public abstract ItineraryDao Dao();

    public static synchronized ItineraryDatabase getInstance(Context mCon){
        if (instance == null) {
            instance =
                  Room.databaseBuilder(mCon.getApplicationContext(),
                                    ItineraryDatabase.class, CONSTANTS.ITINERARY_TABLE)
                            .fallbackToDestructiveMigration()
                            .addCallback(roomCallback)
                            .build();
        }
      
        return instance;
    }

    private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
        @Override
        public void onCreate(@NonNull SupportSQLiteDatabase db) {
            super.onCreate(db);
      
            new PopulateDbAsyncTask(instance).execute();
        }
    };
    private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void> {
        PopulateDbAsyncTask(ItineraryDatabase instance) {
            ItineraryDao dao = instance.Dao();
        }
        @Override
        protected Void doInBackground(Void... voids) {
            return null;
        }
    }
}

我为每张表使用上述代码生成不同的Dao,为了在单个数据库中创建多张表,我为所有表使用了相同的CONSTANTS.ITINERARY_TABLE。如果使用不同的名称,数据不会丢失,但会创建多个数据库。请问如何在单个数据库中创建多张表且重启应用后不丢失数据?


解决方案

核心问题定位

你把表名当成了数据库文件名传入Room.databaseBuilder,这是导致数据丢失和数据库混乱的根本原因。Room中,databaseBuilder的第三个参数是数据库文件的名称(比如travel_app.db),而不是表名。

1. 统一数据库文件名,创建单个数据库

修改databaseBuilder的第三个参数,使用一个固定的数据库名称常量,比如定义CONSTANTS.APP_DATABASE = "travel_app_db",替换原来的表名参数:

public static synchronized ItineraryDatabase getInstance(Context mCon){
    if (instance == null) {
        instance =
              Room.databaseBuilder(mCon.getApplicationContext(),
                                    ItineraryDatabase.class, CONSTANTS.APP_DATABASE) // 替换为数据库文件名
                            .fallbackToDestructiveMigration()
                            .addCallback(roomCallback)
                            .build();
    }
    return instance;
}

2. 在同一个Database类中声明所有实体(多张表)

Room通过@Database注解的entities数组来管理数据库中的所有表,把你需要创建的所有实体类都添加进去:

// 假设还有UserData、NoteData两个实体类,对应两张表
@Database(entities = {ItineraryData.class, UserData.class, NoteData.class}, version = 1, exportSchema = false)
public abstract class ItineraryDatabase extends RoomDatabase {
    // ... 其他代码
}

3. 在Database类中添加所有DAO的抽象方法

每张表对应一个DAO接口,在Database类中声明对应的抽象方法,方便获取各表的操作实例:

public abstract ItineraryDao itineraryDao();
public abstract UserDao userDao();
public abstract NoteDao noteDao();

4. 排查数据丢失的其他潜在原因

  • 检查fallbackToDestructiveMigration():这个方法会在数据库版本升级且无迁移规则时,销毁旧数据库重建,导致数据丢失。开发阶段可以临时使用,正式发布前必须编写迁移逻辑。
  • 确保数据库操作在非主线程执行:Room默认禁止主线程操作数据库,若插入操作在主线程执行会抛出异常(未捕获的话数据不会写入)。推荐用AsyncTask、Coroutines或RxJava执行数据库操作。
  • 验证实体类注解正确性:确保实体类加了@Entity注解,且tableName与DAO查询中的表名一致:
@Entity(tableName = CONSTANTS.ITINERARY_TABLE)
public class ItineraryData {
    @PrimaryKey(autoGenerate = true)
    private int id;
    // 其他字段...
}

内容的提问来源于stack exchange,提问作者Supun Ayeshmantha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 12:20:34